dsl_accessor 0.1.0 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [maiha@wota.jp]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,175 @@
1
+ DslAccessor
2
+ ===========
3
+
4
+ This plugin gives hybrid accessor class methods to classes by DSL like definition,
5
+ here hybrid means getter and setter. The accessor method acts as getter method
6
+ if no argments given, otherwise it acts as setter one with the arguments.
7
+
8
+
9
+ Usage
10
+ =====
11
+
12
+ class Foo
13
+ dsl_accessor "<METHOD NAME>"
14
+ end
15
+
16
+
17
+ Example
18
+ =======
19
+
20
+ class Foo
21
+ dsl_accessor :greeting
22
+ end
23
+
24
+ This code gives 'greeting' class method to Foo class.
25
+
26
+ Foo.greeting # means getter, and the default value is nil.
27
+ => nil
28
+
29
+ Foo.greeting "I'm Foo." # means setter with given arguments
30
+ => "I'm Foo."
31
+
32
+ Foo.greeting
33
+ => "I'm Foo."
34
+
35
+
36
+ Difference
37
+ ==========
38
+
39
+ I'm convinced that you want to propose me to use 'cattr_accessor'.
40
+ Although the difference is just whether we needs '=' operation or not,
41
+ it makes a large different on class definition especially subclass.
42
+
43
+ class Foo
44
+ cattr_accessor :greeting
45
+ end
46
+
47
+ class Bar < Foo
48
+ self.greeting = "I'm bar."
49
+ end
50
+
51
+ We must write redundant code represented by "self." to distinguish
52
+ a local variable and a class method when we use 'cattr_accessor'.
53
+ This is ugly and boring work.
54
+
55
+ class Foo
56
+ dsl_accessor :greeting
57
+ end
58
+
59
+ class Bar < Foo
60
+ greeting "I'm bar."
61
+ end
62
+
63
+ There are no longer redundant prefix code like "self." and "set_".
64
+ Don't you like this dsl-like coding with simple declaration?
65
+
66
+
67
+ Special Options
68
+ ===============
69
+
70
+ 'dsl_accessor' method can take two options, those are :writer and :default.
71
+ "writer" option means callback method used when setter is executed.
72
+ "default" option means default static value or proc that creates some value.
73
+
74
+ class PseudoAR
75
+ dsl_accessor :primary_key, :default=>"id", :writer=>proc{|value| value.to_s}
76
+ dsl_accessor :table_name, :default=>proc{|klass| klass.name.demodulize.underscore.pluralize}
77
+ end
78
+
79
+ class Item < PseudoAR
80
+ end
81
+
82
+ class User < PseudoAR
83
+ primary_key :user_code
84
+ table_name :user_table
85
+ end
86
+
87
+ Item.primary_key # => "id"
88
+ Item.table_name # => "items"
89
+ User.primary_key # => "user_code"
90
+ User.table_name # => :user_table
91
+
92
+ Note that "User.primary_key" return a String by setter proc.
93
+
94
+
95
+ Instance Method
96
+ ===============
97
+
98
+ "instance" option automatically defines its instance method
99
+
100
+ class Search
101
+ dsl_accessor :url, :instance=>true, :default=>"http://localhost/"
102
+ end
103
+
104
+ Search.url # => "http://localhost/"
105
+ Search.new.url # => "http://localhost/"
106
+
107
+ and it uses @options instance variable with special value :options
108
+
109
+ class Window
110
+ dsl_accessor :width, :default=>640, :instance=>:options
111
+ def initialize(options = {})
112
+ @options = options
113
+ end
114
+ end
115
+
116
+ Window.width # => 640
117
+ Window.new.width # => 640
118
+
119
+ window = Window.new(:width=>320)
120
+ window.width # =>320
121
+
122
+
123
+ Install
124
+ =======
125
+
126
+ git://github.com/maiha/dsl_accessor.git
127
+
128
+
129
+ Auto declared mode
130
+ ==================
131
+
132
+ Calling dsl_accessor without args enters auto declared mode.
133
+ In this mode, a method missing means instance method creation.
134
+ This affects only methods with a block and no other args.
135
+
136
+ class Foo
137
+ dsl_accessor # auto declared mode
138
+ foo{1} # define :foo
139
+ bar(a) # NoMethodError
140
+ baz(a){2} # NoMethodError
141
+ end
142
+
143
+ Foo.new.foo # => 1
144
+
145
+ This is useful when you have many methods those are one lined methods.
146
+
147
+ [without auto delared mode]
148
+ class Foo
149
+ def last
150
+ num_pages
151
+ end
152
+
153
+ def first?
154
+ page == 1
155
+ end
156
+
157
+ def offset
158
+ model.proxy_options[:offset]
159
+ end
160
+ end
161
+
162
+ [with auto delared mode]
163
+ class Foo
164
+ dsl_accessor
165
+ last {num_pages}
166
+ first? {page == 1}
167
+ offset {model.proxy_options[:offset]}
168
+ end
169
+
170
+
171
+
172
+ Author
173
+ ======
174
+ Maiha <maiha@wota.jp>
175
+
data/Rakefile CHANGED
@@ -1,49 +1,74 @@
1
- require 'rubygems'
2
1
  require 'rake'
3
- require 'rake/clean'
4
2
  require 'rake/testtask'
5
- require 'rake/packagetask'
6
- require 'rake/gempackagetask'
7
3
  require 'rake/rdoctask'
8
- require 'rake/contrib/rubyforgepublisher'
9
- require 'fileutils'
10
- require 'hoe'
11
- include FileUtils
12
- require File.join(File.dirname(__FILE__), 'lib', 'dsl_accessor', 'version')
13
-
14
- AUTHOR = ['Maiha', 'Alex Wayne'] # can also be an array of Authors
15
- EMAIL = "anna@wota.jp"
16
- DESCRIPTION = "This gem gives hybrid accessor class methods to classes by DSL like definition."
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the dsl_accessor plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the dsl_accessor plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'DslAccessor'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+
25
+ ######################################################################
26
+ ### for gem
27
+
28
+ require 'rubygems'
29
+ require 'rake/gempackagetask'
30
+
17
31
  GEM_NAME = "dsl_accessor"
18
- RUBYFORGE_PROJECT = "dsl-accessor"
19
- HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
20
- RELEASE_TYPES = %w( gem )
21
-
22
-
23
- NAME = "dsl_accessor"
24
- REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
25
- VERS = ENV['VERSION'] || (DslAccessor::VERSION::STRING + (REV ? ".#{REV}" : ""))
26
- CLEAN.include ['**/.*.sw?', '*.gem', '.config']
27
- RDOC_OPTS = ['--quiet', '--title', "dsl_accessor documentation",
28
- "--opname", "index.html",
29
- "--line-numbers",
30
- "--main", "README",
31
- "--inline-source"]
32
-
33
- # Generate all the Rake tasks
34
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
35
- hoe = Hoe.new(GEM_NAME, VERS) do |p|
36
- p.author = AUTHOR
37
- p.description = DESCRIPTION
38
- p.email = EMAIL
39
- p.summary = DESCRIPTION
40
- p.url = HOMEPATH
41
- p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
42
- p.test_globs = ["test/**/*_test.rb"]
43
- p.clean_globs = CLEAN #An array of file patterns to delete on clean.
44
-
45
- # == Optional
46
- #p.changes - A description of the release's latest changes.
47
- p.extra_deps = %w( activesupport )
48
- #p.spec_extras - A hash of extra values to set in the gemspec.
49
- end
32
+ AUTHOR = "maiha"
33
+ EMAIL = "maiha@wota.jp"
34
+ HOMEPAGE = "http://github.com/maiha/dsl_accessor"
35
+ SUMMARY = "This plugin gives hybrid accessor class methods to classes by DSL like definition"
36
+ GEM_VERSION = "0.3.3"
37
+
38
+ spec = Gem::Specification.new do |s|
39
+ # s.rubyforge_project = 'merb'
40
+ s.name = GEM_NAME
41
+ s.version = GEM_VERSION
42
+ s.platform = Gem::Platform::RUBY
43
+ s.has_rdoc = true
44
+ s.extra_rdoc_files = ["README", "LICENSE"]
45
+ s.summary = SUMMARY
46
+ s.description = s.summary
47
+ s.author = AUTHOR
48
+ s.email = EMAIL
49
+ s.homepage = HOMEPAGE
50
+ s.require_path = 'lib'
51
+ s.files = %w(LICENSE README Rakefile) + Dir.glob("{core_ext,lib,spec,tasks,test}/**/*")
52
+ end
53
+
54
+ Rake::GemPackageTask.new(spec) do |pkg|
55
+ pkg.gem_spec = spec
56
+ end
57
+
58
+ desc "Install the gem"
59
+ task :install do
60
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
61
+ end
62
+
63
+ desc "Uninstall the gem"
64
+ task :uninstall do
65
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
66
+ end
67
+
68
+ desc "Create a gemspec file"
69
+ task :gemspec do
70
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
71
+ file.puts spec.to_ruby
72
+ end
73
+ end
74
+
@@ -0,0 +1,93 @@
1
+ module DslAccessor
2
+ def dsl_accessor(*args)
3
+ options = args.last.is_a?(Hash) ? args.pop : {}
4
+
5
+ # mark auto_declared
6
+ name = args.shift or
7
+ return @dsl_accessor_auto_declared = true
8
+
9
+ options[:default] = args.shift unless args.empty?
10
+
11
+ case options[:instance]
12
+ when nil
13
+ # nop
14
+ when :options
15
+ module_eval(<<-EOS, "(__DSL_ACCESSOR__)", 1)
16
+ def #{ name }
17
+ unless @options
18
+ raise TypeError, "DSL Error: missing @options for %s##{name}" % self.class.name
19
+ end
20
+ @options[:#{ name }] || self.class.#{ name }
21
+ end
22
+ EOS
23
+ when true
24
+ delegate name, :to=>"self.class"
25
+ else
26
+ raise TypeError, "DSL Error: :instance should be true or :instance, but got `%s' class" % options[:instance].class
27
+ end
28
+
29
+ raise TypeError, "DSL Error: options should be a hash. but got `#{options.class}'" unless options.is_a?(Hash)
30
+ writer = options[:writer] || options[:setter]
31
+ writer =
32
+ case writer
33
+ when NilClass then Proc.new{|value| value}
34
+ when Symbol then Proc.new{|value| __send__(writer, value)}
35
+ when Proc then writer
36
+ else raise TypeError, "DSL Error: writer should be a symbol or proc. but got `#{options[:writer].class}'"
37
+ end
38
+ write_inheritable_attribute(:"#{name}_writer", writer)
39
+
40
+ default =
41
+ case options[:default]
42
+ when NilClass then nil
43
+ when [] then Proc.new{[]}
44
+ when {} then Proc.new{{}}
45
+ when Symbol then Proc.new{__send__(options[:default])}
46
+ when Proc then options[:default]
47
+ else Proc.new{options[:default]}
48
+ end
49
+ write_inheritable_attribute(:"#{name}_default", default)
50
+
51
+ (class << self; self end).class_eval do
52
+ define_method("#{name}=") do |value|
53
+ writer = read_inheritable_attribute(:"#{name}_writer")
54
+ value = writer.call(value) if writer
55
+ write_inheritable_attribute(:"#{name}", value)
56
+ end
57
+
58
+ define_method(name) do |*values|
59
+ if values.empty?
60
+ # getter method
61
+ key = :"#{name}"
62
+ if !inheritable_attributes.has_key?(key)
63
+ default = read_inheritable_attribute(:"#{name}_default")
64
+ value = default ? default.call(self) : nil
65
+ __send__("#{name}=", value)
66
+ end
67
+ read_inheritable_attribute(key)
68
+ else
69
+ # setter method
70
+ __send__("#{name}=", *values)
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ private
77
+ def dsl_accessor_auto_declared?
78
+ !!@dsl_accessor_auto_declared
79
+ end
80
+
81
+ def method_missing(*args, &block)
82
+ if dsl_accessor_auto_declared? and args.size == 1 and block
83
+ define_method(*args, &block)
84
+ else
85
+ super
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ class Class
92
+ include DslAccessor
93
+ end
@@ -0,0 +1,140 @@
1
+ # Retain for backward compatibility. Methods are now included in Class.
2
+ module ClassInheritableAttributes # :nodoc:
3
+ end
4
+
5
+ # Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
6
+ # their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
7
+ # to, for example, an array without those additions being shared with either their parent, siblings, or
8
+ # children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
9
+ class Class # :nodoc:
10
+ def class_inheritable_reader(*syms)
11
+ syms.each do |sym|
12
+ next if sym.is_a?(Hash)
13
+ class_eval <<-EOS
14
+ def self.#{sym}
15
+ read_inheritable_attribute(:#{sym})
16
+ end
17
+
18
+ def #{sym}
19
+ self.class.#{sym}
20
+ end
21
+ EOS
22
+ end
23
+ end
24
+
25
+ def class_inheritable_writer(*syms)
26
+ options = syms.last.is_a?(::Hash) ? syms.pop : {}
27
+ syms.each do |sym|
28
+ class_eval <<-EOS
29
+ def self.#{sym}=(obj)
30
+ write_inheritable_attribute(:#{sym}, obj)
31
+ end
32
+
33
+ #{"
34
+ def #{sym}=(obj)
35
+ self.class.#{sym} = obj
36
+ end
37
+ " unless options[:instance_writer] == false }
38
+ EOS
39
+ end
40
+ end
41
+
42
+ def class_inheritable_array_writer(*syms)
43
+ options = syms.last.is_a?(::Hash) ? syms.pop : {}
44
+ syms.each do |sym|
45
+ class_eval <<-EOS
46
+ def self.#{sym}=(obj)
47
+ write_inheritable_array(:#{sym}, obj)
48
+ end
49
+
50
+ #{"
51
+ def #{sym}=(obj)
52
+ self.class.#{sym} = obj
53
+ end
54
+ " unless options[:instance_writer] == false }
55
+ EOS
56
+ end
57
+ end
58
+
59
+ def class_inheritable_hash_writer(*syms)
60
+ options = syms.last.is_a?(::Hash) ? syms.pop : {}
61
+ syms.each do |sym|
62
+ class_eval <<-EOS
63
+ def self.#{sym}=(obj)
64
+ write_inheritable_hash(:#{sym}, obj)
65
+ end
66
+
67
+ #{"
68
+ def #{sym}=(obj)
69
+ self.class.#{sym} = obj
70
+ end
71
+ " unless options[:instance_writer] == false }
72
+ EOS
73
+ end
74
+ end
75
+
76
+ def class_inheritable_accessor(*syms)
77
+ class_inheritable_reader(*syms)
78
+ class_inheritable_writer(*syms)
79
+ end
80
+
81
+ def class_inheritable_array(*syms)
82
+ class_inheritable_reader(*syms)
83
+ class_inheritable_array_writer(*syms)
84
+ end
85
+
86
+ def class_inheritable_hash(*syms)
87
+ class_inheritable_reader(*syms)
88
+ class_inheritable_hash_writer(*syms)
89
+ end
90
+
91
+ def inheritable_attributes
92
+ @inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
93
+ end
94
+
95
+ def write_inheritable_attribute(key, value)
96
+ if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
97
+ @inheritable_attributes = {}
98
+ end
99
+ inheritable_attributes[key] = value
100
+ end
101
+
102
+ def write_inheritable_array(key, elements)
103
+ write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
104
+ write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
105
+ end
106
+
107
+ def write_inheritable_hash(key, hash)
108
+ write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
109
+ write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
110
+ end
111
+
112
+ def read_inheritable_attribute(key)
113
+ inheritable_attributes[key]
114
+ end
115
+
116
+ def reset_inheritable_attributes
117
+ @inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
118
+ end
119
+
120
+ private
121
+ # Prevent this constant from being created multiple times
122
+ EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
123
+
124
+ def inherited_with_inheritable_attributes(child)
125
+ inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
126
+
127
+ if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
128
+ new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
129
+ else
130
+ new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
131
+ memo.update(key => value.duplicable? ? value.dup : value)
132
+ end
133
+ end
134
+
135
+ child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
136
+ end
137
+
138
+ alias inherited_without_inheritable_attributes inherited
139
+ alias inherited inherited_with_inheritable_attributes
140
+ end
@@ -0,0 +1,43 @@
1
+ class Object
2
+ # Can you safely .dup this object?
3
+ # False for nil, false, true, symbols, and numbers; true otherwise.
4
+ def duplicable?
5
+ true
6
+ end
7
+ end
8
+
9
+ class NilClass #:nodoc:
10
+ def duplicable?
11
+ false
12
+ end
13
+ end
14
+
15
+ class FalseClass #:nodoc:
16
+ def duplicable?
17
+ false
18
+ end
19
+ end
20
+
21
+ class TrueClass #:nodoc:
22
+ def duplicable?
23
+ false
24
+ end
25
+ end
26
+
27
+ class Symbol #:nodoc:
28
+ def duplicable?
29
+ false
30
+ end
31
+ end
32
+
33
+ class Numeric #:nodoc:
34
+ def duplicable?
35
+ false
36
+ end
37
+ end
38
+
39
+ class Class #:nodoc:
40
+ def duplicable?
41
+ false
42
+ end
43
+ end
@@ -0,0 +1,95 @@
1
+ class Module
2
+ # Provides a delegate class method to easily expose contained objects' methods
3
+ # as your own. Pass one or more methods (specified as symbols or strings)
4
+ # and the name of the target object as the final <tt>:to</tt> option (also a symbol
5
+ # or string). At least one method and the <tt>:to</tt> option are required.
6
+ #
7
+ # Delegation is particularly useful with Active Record associations:
8
+ #
9
+ # class Greeter < ActiveRecord::Base
10
+ # def hello() "hello" end
11
+ # def goodbye() "goodbye" end
12
+ # end
13
+ #
14
+ # class Foo < ActiveRecord::Base
15
+ # belongs_to :greeter
16
+ # delegate :hello, :to => :greeter
17
+ # end
18
+ #
19
+ # Foo.new.hello # => "hello"
20
+ # Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
21
+ #
22
+ # Multiple delegates to the same target are allowed:
23
+ #
24
+ # class Foo < ActiveRecord::Base
25
+ # belongs_to :greeter
26
+ # delegate :hello, :goodbye, :to => :greeter
27
+ # end
28
+ #
29
+ # Foo.new.goodbye # => "goodbye"
30
+ #
31
+ # Methods can be delegated to instance variables, class variables, or constants
32
+ # by providing them as a symbols:
33
+ #
34
+ # class Foo
35
+ # CONSTANT_ARRAY = [0,1,2,3]
36
+ # @@class_array = [4,5,6,7]
37
+ #
38
+ # def initialize
39
+ # @instance_array = [8,9,10,11]
40
+ # end
41
+ # delegate :sum, :to => :CONSTANT_ARRAY
42
+ # delegate :min, :to => :@@class_array
43
+ # delegate :max, :to => :@instance_array
44
+ # end
45
+ #
46
+ # Foo.new.sum # => 6
47
+ # Foo.new.min # => 4
48
+ # Foo.new.max # => 11
49
+ #
50
+ # Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
51
+ # is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
52
+ # delegated to.
53
+ #
54
+ # Person = Struct.new(:name, :address)
55
+ #
56
+ # class Invoice < Struct.new(:client)
57
+ # delegate :name, :address, :to => :client, :prefix => true
58
+ # end
59
+ #
60
+ # john_doe = Person.new("John Doe", "Vimmersvej 13")
61
+ # invoice = Invoice.new(john_doe)
62
+ # invoice.client_name # => "John Doe"
63
+ # invoice.client_address # => "Vimmersvej 13"
64
+ #
65
+ # It is also possible to supply a custom prefix.
66
+ #
67
+ # class Invoice < Struct.new(:client)
68
+ # delegate :name, :address, :to => :client, :prefix => :customer
69
+ # end
70
+ #
71
+ # invoice = Invoice.new(john_doe)
72
+ # invoice.customer_name # => "John Doe"
73
+ # invoice.customer_address # => "Vimmersvej 13"
74
+ #
75
+ def delegate(*methods)
76
+ options = methods.pop
77
+ unless options.is_a?(Hash) && to = options[:to]
78
+ raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
79
+ end
80
+
81
+ if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
82
+ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
83
+ end
84
+
85
+ prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_"
86
+
87
+ methods.each do |method|
88
+ module_eval(<<-EOS, "(__DELEGATION__)", 1)
89
+ def #{prefix}#{method}(*args, &block)
90
+ #{to}.__send__(#{method.inspect}, *args, &block)
91
+ end
92
+ EOS
93
+ end
94
+ end
95
+ end