Permalink
Browse files

init commit

  • Loading branch information...
1 parent 4fe4e2e commit c54e9d3ff7ec18299bea8850063669f4b3ce9e0d @prepor prepor committed Mar 23, 2011
Showing with 453 additions and 29 deletions.
  1. +4 −0 Gemfile
  2. +55 −0 Gemfile.lock
  3. +93 −0 README.md
  4. +0 −19 README.rdoc
  5. +7 −5 Rakefile
  6. 0 lib/ruby-interface.rb
  7. +8 −0 lib/ruby-interface/yard.rb
  8. +71 −0 lib/ruby_interface.rb
  9. +90 −0 ruby-interface.gemspec
  10. +125 −5 spec/ruby-interface_spec.rb
View
@@ -11,4 +11,8 @@ group :development do
gem "bundler", "~> 1.0.0"
gem "jeweler", "~> 1.5.2"
gem "rcov", ">= 0"
+ gem "bluecloth"
+ gem "undev"
end
+
+gemspec
View
@@ -0,0 +1,55 @@
+PATH
+ remote: .
+ specs:
+ ruby-interface (0.0.1)
+ activesupport (> 0.1)
+ i18n (> 0.1)
+ ruby-interface
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ activesupport (3.0.5)
+ bluecloth (2.1.0)
+ builder (3.0.0)
+ diff-lcs (1.1.2)
+ geminabox (0.2.11)
+ builder
+ sinatra
+ git (1.2.5)
+ i18n (0.5.0)
+ jeweler (1.5.2)
+ bundler (~> 1.0.0)
+ git (>= 1.2.5)
+ rake
+ rack (1.2.2)
+ rake (0.8.7)
+ rcov (0.9.9)
+ rspec (2.3.0)
+ rspec-core (~> 2.3.0)
+ rspec-expectations (~> 2.3.0)
+ rspec-mocks (~> 2.3.0)
+ rspec-core (2.3.1)
+ rspec-expectations (2.3.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.3.0)
+ sinatra (1.2.1)
+ rack (~> 1.1)
+ tilt (>= 1.2.2, < 2.0)
+ tilt (1.2.2)
+ undev (0.0.7)
+ geminabox
+ yard (0.6.5)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ bluecloth
+ bundler (~> 1.0.0)
+ jeweler (~> 1.5.2)
+ rcov
+ rspec (~> 2.3.0)
+ ruby-interface!
+ undev
+ yard (~> 0.6.0)
View
@@ -0,0 +1,93 @@
+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, возвращающий родительский объект. У класса интерфейса есть <tt>interface_base</tt>, возвращающий класс, куда интерфейс был заинклужен.
+
+Помимо инстанс метода, создается так же класс-метод. В него можно передать блок, который выполнится в скоупе класса интерфейса. Сам метод возвращает класс интерфейса.
+
+ 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
+
+При наследовании класса с интерфейсом, создается новый класс интерфейса и наследуется от предыдущего, т.е. повторяет иерархию класса, в который он включен.
+
+Если в блоке <tt>interface</tt> вызывается метод <tt>interfaced</tt>, то исполнение блока, передаваемого <tt>interfaced</tt>
+происходит после добавления интерфейса в класс, в контексте этого класса.
+
+Пример:
+
+ 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"
+
+В каждом модуле может быть определено произвольное количество интерфейсов
View
@@ -1,19 +0,0 @@
-= ruby-interface
-
-Description goes here.
-
-== Contributing to ruby-interface
-
-* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
-* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
-* Fork the project
-* Start a feature/bugfix branch
-* Commit and push until you are happy with your contribution
-* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
-* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
-
-== Copyright
-
-Copyright (c) 2011 Andrew Rudenko. See LICENSE.txt for
-further details.
-
View
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
require 'rubygems'
require 'bundler'
begin
@@ -13,16 +15,16 @@ require 'jeweler'
Jeweler::Tasks.new do |gem|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
gem.name = "ruby-interface"
- gem.homepage = "http://github.com/prepor/ruby-interface"
+ gem.homepage = "http://git.undev.cc/small-things/ruby-interface"
gem.license = "MIT"
- gem.summary = %Q{TODO: one-line summary of your gem}
- gem.description = %Q{TODO: longer description of your gem}
+ gem.summary = %Q{Более комплексные руби-интерфейсы, чем просто миксины}
+ gem.description = %Q{Более комплексные руби-интерфейсы, чем просто миксины}
gem.email = "ceo@prepor.ru"
gem.authors = ["Andrew Rudenko"]
# Include your dependencies below. Runtime dependencies are required when using your gem,
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
- # gem.add_runtime_dependency 'jabber4r', '> 0.1'
- # gem.add_development_dependency 'rspec', '> 1.2.3'
+ gem.add_runtime_dependency 'i18n', '> 0.1'
+ gem.add_runtime_dependency 'activesupport', '> 0.1'
end
Jeweler::RubygemsDotOrgTasks.new
View
No changes.
@@ -0,0 +1,8 @@
+class RubyInterfaceHandler < YARD::Handlers::Ruby::Base
+ handles method_call(:interface)
+
+ def process
+ parse_block(statement.last.last)
+ rescue YARD::Handlers::NamespaceMissingError
+ end
+end
View
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+require 'active_support/core_ext/class/attribute'
+require 'active_support/core_ext/string/inflections'
+
+module RubyInterface
+ def interface(method_name, &interface_body)
+ mod_inst = self.const_set("#{method_name.to_s.camelize}InstanceMethods", Module.new)
+ mod_inst.module_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{method_name}
+ @#{method_name}_interface ||= self.class.#{method_name}_interface.new(self)
+ end
+ EOT
+
+
+ mod_class = self.const_set("#{method_name.to_s.camelize}ClassMethods", Module.new)
+ mod_class.module_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{method_name}(&blk)
+ self.#{method_name}_interface.class_eval(&blk) if blk
+ self.#{method_name}_interface
+ end
+
+ def inherited(subclass)
+ new_class = subclass.const_set("#{method_name.to_s.camelize}InterfaceClass", Class.new(self.#{method_name}_interface))
+ new_class.interface_base = subclass
+ subclass.#{method_name}_interface = new_class
+ super
+ end
+ EOT
+
+ interface_module = self
+
+ add_interface do |base|
+ base.send(:class_attribute, "#{method_name}_interface")
+ interface_class = base.const_set("#{method_name.to_s.camelize}InterfaceClass", Class.new(RubyInterface::InterfaceClass))
+ interface_class.interface_base = base
+ interface_class.class_eval(&interface_body) if interface_body
+ base.send("#{method_name}_interface=", interface_class)
+ base.extend mod_class
+ base.send :include, mod_inst
+ base.class_eval(&interface_class.interfaced) if interface_class.interfaced
+ end
+
+ interface_module.define_singleton_method(:included) do |base|
+ @_deps.each {|d| d.call(base)}
+ end
+ end
+
+ private
+ def add_interface &block
+ @_deps ||= []
+ @_deps << block
+ end
+
+ class InterfaceClass
+ class_attribute :interface_base
+ attr_accessor :owner
+ def initialize(owner)
+ @owner = owner
+ end
+
+ class << self
+ def interfaced(&block)
+ if block_given?
+ @_interfaced_block = block
+ else
+ @_interfaced_block
+ end
+ end
+ end
+ end
+end
View
@@ -0,0 +1,90 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{ruby-interface}
+ s.version = "0.0.1"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Andrew Rudenko"]
+ s.date = %q{2011-03-23}
+ s.description = %q{Более комплексные руби-интерфейсы, чем просто миксины}
+ s.email = %q{ceo@prepor.ru}
+ s.extra_rdoc_files = [
+ "LICENSE.txt",
+ "README.rdoc"
+ ]
+ s.files = [
+ ".document",
+ ".rspec",
+ "Gemfile",
+ "LICENSE.txt",
+ "README.rdoc",
+ "Rakefile",
+ "VERSION",
+ "lib/ruby-interface.rb",
+ "spec/ruby-interface_spec.rb",
+ "spec/spec_helper.rb"
+ ]
+ s.homepage = %q{http://git.undev.cc/small-things/ruby-interface}
+ s.licenses = ["MIT"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.3.7}
+ s.summary = %q{Более комплексные руби-интерфейсы, чем просто миксины}
+ s.test_files = [
+ "spec/ruby-interface_spec.rb",
+ "spec/spec_helper.rb"
+ ]
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_runtime_dependency(%q<ruby-interface>, [">= 0"])
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
+ s.add_development_dependency(%q<rcov>, [">= 0"])
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
+ s.add_development_dependency(%q<rcov>, [">= 0"])
+ s.add_runtime_dependency(%q<i18n>, ["> 0.1"])
+ s.add_runtime_dependency(%q<activesupport>, ["> 0.1"])
+ else
+ s.add_dependency(%q<ruby-interface>, [">= 0"])
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
+ s.add_dependency(%q<rcov>, [">= 0"])
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
+ s.add_dependency(%q<rcov>, [">= 0"])
+ s.add_dependency(%q<i18n>, ["> 0.1"])
+ s.add_dependency(%q<activesupport>, ["> 0.1"])
+ end
+ else
+ s.add_dependency(%q<ruby-interface>, [">= 0"])
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
+ s.add_dependency(%q<rcov>, [">= 0"])
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
+ s.add_dependency(%q<rcov>, [">= 0"])
+ s.add_dependency(%q<i18n>, ["> 0.1"])
+ s.add_dependency(%q<activesupport>, ["> 0.1"])
+ end
+end
+
Oops, something went wrong.

0 comments on commit c54e9d3

Please sign in to comment.