Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Ruby
tree: 618dd465f3
Failed to load latest commit information.
lib version bump
spec удаляем мусор
.document Initial commit to ruby-interface.
.gitignore Initial commit to ruby-interface.
.rspec Initial commit to ruby-interface.
Gemfile -jeweler
Gemfile.lock
LICENSE.txt Initial commit to ruby-interface.
README.md init commit
Rakefile -jeweler
ruby-interface.gemspec gemspec fixed

README.md

RubyInterface

Простенький патерн определения интерфейсов в руби. В противовес стандартным миксинам, для каждого интерфейса создается свой класс и соответсвенно экземпляр класса для каждого объекта с интерфейсом.

module Tree
  extend RubyInterface
  interface :tree do
    include Enumerable
    attr_accessor :parent

    def childs
      @childs ||= []
    end

    def each(&blk)
      blk.call(owner)
      childs.each { |v| v.tree.each(&blk) }
    end

    def set_parent(parent)
      parent.tree.childs << owner
      @parent = parent
    end
  end
end

class A
  include Tree
end

При разработке интерфейса не нужно задумываться о конфликтах имен переменных, методов, можно делать все что угодно. Аргументом к методу interface передается название метода, по которому этот интерфейс будет доступен.

a = A.new
b = A.new

a.tree.set_parent b
b.tree.childs # => [a]
b.tree.map { |o| o } # => [b, a]

А при использовании методов относящихся к интерфейсу мы явно видим к какому же интерфейсу он относится. Всем профит!

В интерфейсе доступен метод owner, возвращающий родительский объект. У класса интерфейса есть interface_base, возвращающий класс, куда интерфейс был заинклужен.

Помимо инстанс метода, создается так же класс-метод. В него можно передать блок, который выполнится в скоупе класса интерфейса. Сам метод возвращает класс интерфейса.

module StateMachine
  extend RubyInterface
  interface :state_machine do
    def self.state(name)
      puts "New state #{name}"
    end
  end
end

class A
  include StateMachine

  state_machine do
    state(:parked) # => New state parked
    state(:idling) # => New state idling
  end
end

При наследовании класса с интерфейсом, создается новый класс интерфейса и наследуется от предыдущего, т.е. повторяет иерархию класса, в который он включен.

Если в блоке interface вызывается метод interfaced, то исполнение блока, передаваемого interfaced происходит после добавления интерфейса в класс, в контексте этого класса.

Пример:

 module A
   extend RubyInterface
   interface :int do
     interfaced do
       def baz
         self.class.int_interface.foo
       end
     end

     def self.foo
       "bar"
     end
   end
 end

 class B
   include A
 end

 B.new.baz # => "bar"

В каждом модуле может быть определено произвольное количество интерфейсов

Something went wrong with that request. Please try again.