genki-dsl_accessor 0.4.2

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/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [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,209 @@
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
+ Install
10
+ =======
11
+
12
+ gem install dsl_accessor
13
+
14
+
15
+ Usage
16
+ =====
17
+
18
+ class Foo
19
+ dsl_accessor "<METHOD NAME>" (, default_value)
20
+ end
21
+
22
+
23
+ Example
24
+ =======
25
+
26
+ class Foo
27
+ dsl_accessor :greeting
28
+ end
29
+
30
+ This code gives 'greeting' class method to Foo class.
31
+
32
+ Foo.greeting # means getter, and the default value is nil.
33
+ => nil
34
+
35
+ Foo.greeting "I'm Foo." # means setter with given arguments
36
+ => "I'm Foo."
37
+
38
+ Foo.greeting
39
+ => "I'm Foo."
40
+
41
+
42
+ Difference
43
+ ==========
44
+
45
+ I am convinced that you want to propose me to use 'cattr_accessor'.
46
+ Although the difference is just whether we needs '=' operation or not,
47
+ it makes a large different on class definition especially subclass.
48
+
49
+ class Foo
50
+ cattr_accessor :greeting
51
+ end
52
+
53
+ class Bar < Foo
54
+ self.greeting = "I am bar."
55
+ end
56
+
57
+ We must write redundant code represented by "self." to distinguish
58
+ a local variable and a class method when we use 'cattr_accessor'.
59
+ This is ugly and boring work.
60
+
61
+ class Foo
62
+ dsl_accessor :greeting
63
+ end
64
+
65
+ class Bar < Foo
66
+ greeting "I am bar."
67
+ end
68
+
69
+ There are no longer redundant prefix code like "self." and "set_".
70
+ How about this dsl-like coding with simple declaration?
71
+
72
+
73
+ Special Options
74
+ ===============
75
+
76
+ 'dsl_accessor' method can take two options, those are :writer and :default.
77
+ "writer" option means callback method used when setter is executed.
78
+ "default" option means default static value or proc that creates some value.
79
+
80
+ class PseudoAR
81
+ dsl_accessor :primary_key, :default=>"id", :writer=>proc{|value| value.to_s}
82
+ dsl_accessor :table_name, :default=>proc{|klass| klass.name.demodulize.underscore.pluralize}
83
+ end
84
+
85
+ class Item < PseudoAR
86
+ end
87
+
88
+ class User < PseudoAR
89
+ primary_key :user_code
90
+ table_name :user_table
91
+ end
92
+
93
+ Item.primary_key # => "id"
94
+ Item.table_name # => "items"
95
+ User.primary_key # => "user_code"
96
+ User.table_name # => :user_table
97
+
98
+ Note that "User.primary_key" return a String by setter proc.
99
+
100
+
101
+ Instance Method
102
+ ===============
103
+
104
+ "instance" option automatically defines its instance method
105
+
106
+ class Search
107
+ dsl_accessor :url, :instance=>true, :default=>"http://localhost/"
108
+ end
109
+
110
+ Search.url # => "http://localhost/"
111
+ Search.new.url # => "http://localhost/"
112
+
113
+ and it uses @options instance variable with special value :options
114
+
115
+ class Window
116
+ dsl_accessor :width, :default=>640, :instance=>:options
117
+ def initialize(options = {})
118
+ @options = options
119
+ end
120
+ end
121
+
122
+ Window.width # => 640
123
+ Window.new.width # => 640
124
+
125
+ window = Window.new(:width=>320)
126
+ window.width # =>320
127
+
128
+
129
+ Auto declared mode
130
+ ==================
131
+
132
+ It was removed at version 0.4.
133
+ In 0.4.1 or higher, use dsl_accessor block instead.
134
+
135
+
136
+ with block
137
+ ==========
138
+
139
+ dsl_accessor method accepts block for auto declared mode.
140
+ In this mode, we can define methods like dsl.
141
+
142
+ [NOTE]
143
+ 1. This affects only methods with a block and no other args.
144
+
145
+ class Foo
146
+ dsl_accessor do
147
+ foo {1} # Foo.foo is defined
148
+ bar(a) # NoMethodError
149
+ baz(a) {2} # NoMethodError
150
+ end
151
+ end
152
+
153
+ 2. When :instance is passed with block, it affects instance methods.
154
+
155
+ class Foo
156
+ dsl_accessor :instance do
157
+ foo {1} # Foo#foo is defined
158
+ bar(a) # NoMethodError (same as class)
159
+ end
160
+ end
161
+
162
+ 3. This will damage on your class cause it easily updates existing methods.
163
+
164
+ Foo.name # => 'Foo'
165
+ class Foo
166
+ dsl_accessor do
167
+ name {1}
168
+ end
169
+ end
170
+ Foo.name # => 1
171
+
172
+
173
+ Although there is a risk on above, it helps you when many one-lined methods exist.
174
+
175
+ class Foo
176
+ def last
177
+ num_pages
178
+ end
179
+
180
+ def first?
181
+ page == 1
182
+ end
183
+
184
+ def offset
185
+ model.proxy_options[:offset]
186
+ end
187
+ end
188
+
189
+ Refactored with dsl_accessor
190
+
191
+ class Foo
192
+ dsl_accessor :instance do
193
+ last {num_pages}
194
+ first? {page == 1}
195
+ offset {model.proxy_options[:offset]}
196
+ end
197
+ end
198
+
199
+
200
+ Homepage
201
+ ========
202
+
203
+ http://github.com/maiha/dsl_accessor
204
+
205
+
206
+ Author
207
+ ======
208
+ Maiha <maiha@wota.jp>
209
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -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
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "dsl_accessor/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "genki-dsl_accessor"
7
+ s.version = DslAccessor::VERSION
8
+ s.authors = ["genki"]
9
+ s.email = ["genki@s21g.com"]
10
+ s.homepage = "https://github.com/genki/dsl_accessor"
11
+ s.summary = %q{This plugin gives hybrid accessor class methods to classes by DSL like definition}
12
+ s.description = %q{This plugin gives hybrid accessor class methods to classes by DSL like definition}
13
+
14
+ s.rubyforge_project = "dsl_accessor"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "optionize", ">= 0.1.0"
22
+
23
+ s.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,19 @@
1
+ unless Module.new.respond_to?(:delegate)
2
+ require File.dirname(__FILE__) + "/../core_ext/module/delegation"
3
+ end
4
+
5
+ require File.dirname(__FILE__) + '/dsl_accessor/version'
6
+ require File.dirname(__FILE__) + '/dsl_accessor/auto_declare'
7
+ require File.dirname(__FILE__) + '/dsl_accessor/accessor'
8
+ require File.dirname(__FILE__) + '/dsl_accessor/stores'
9
+
10
+ class Module
11
+ include DslAccessor
12
+ include DslAccessor::Stores::Basic
13
+ end
14
+
15
+ class Class
16
+ include DslAccessor
17
+ include DslAccessor::Stores::Inherit
18
+ end
19
+
@@ -0,0 +1,117 @@
1
+ require 'optionize'
2
+
3
+ module DslAccessor
4
+ def dsl_accessor_reader(key, *args, &block)
5
+ key = key.to_s
6
+ if !args.empty? or block_given?
7
+ # setter method
8
+ dsl_accessor_writer(key, *args, &block)
9
+ else
10
+ # getter method
11
+ if !dsl_accessor_key?(key)
12
+ # load default value
13
+ default = dsl_accessor_get("#{key}_default")
14
+ value = default ? default.call : nil
15
+ dsl_accessor_writer(key, value)
16
+ end
17
+ dsl_accessor_get(key)
18
+ end
19
+ end
20
+
21
+ def dsl_accessor_writer(key, *args, &block)
22
+ case args.size
23
+ when 0
24
+ unless block_given?
25
+ raise ArgumentError, "'#{key}=' expected one argument or block, but nothing passed"
26
+ end
27
+ writer = dsl_accessor_get("#{key}_writer")
28
+ value = writer ? writer.call(block) : block
29
+ dsl_accessor_set("#{key}", value)
30
+ when 1
31
+ if block_given?
32
+ raise ArgumentError, "'#{key}=' got both arg and block, specify only one of them"
33
+ end
34
+
35
+ writer = dsl_accessor_get("#{key}_writer")
36
+ value = writer ? writer.call(*args) : args.first
37
+ dsl_accessor_set("#{key}", value)
38
+ else
39
+ raise ArgumentError, "'#{key}=' expected one argument, but got #{args.size} args"
40
+ end
41
+ end
42
+
43
+ def dsl_accessor(*args, &block)
44
+ opts = Optionize.new(args, :name, :default)
45
+ name = opts.name
46
+
47
+ if block
48
+ case name
49
+ when :class, NilClass
50
+ AutoDeclare::DefineClassMethod.new(self, &block)
51
+ when :instance
52
+ AutoDeclare::DefineInstanceMethod.new(self, &block)
53
+ else
54
+ raise ArgumentError, "dsl_accessor block expects :class or :instance for arg, but got #{name.inspect}"
55
+ end
56
+ return
57
+ end
58
+
59
+ if !name
60
+ raise ArgumentError, "dsl_accessor expects at least one arg"
61
+ end
62
+
63
+ writer =
64
+ case opts.writer
65
+ when NilClass then Proc.new{|value| value}
66
+ when Symbol then Proc.new{|value| __send__(opts.writer, value)}
67
+ when Proc then opts.writer
68
+ else raise TypeError, "DSL Error: writer should be a symbol or proc. but got `#{opts.writer.class}'"
69
+ end
70
+ dsl_accessor_set("#{name}_writer", writer)
71
+
72
+ default =
73
+ case opts.default
74
+ when NilClass then nil
75
+ when [] then Proc.new{[]}
76
+ when {} then Proc.new{{}}
77
+ when Symbol then Proc.new{__send__(opts.default)}
78
+ when Proc then opts.default
79
+ else Proc.new{opts.default}
80
+ end
81
+ dsl_accessor_set("#{name}_default", default)
82
+
83
+ meta_class = (class << self; self; end)
84
+
85
+ if opts.instance and !is_a?(Class)
86
+ raise ArgumentError, ":instance option is implemented in only Class"
87
+ end
88
+
89
+ case opts.instance
90
+ when nil
91
+ # nop
92
+ when true
93
+ delegate name, :to=>"self.class"
94
+ when Symbol
95
+ module_eval(<<-EOS, "(__DSL_ACCESSOR__)", 1)
96
+ def #{ name }
97
+ @#{opts.instance} or
98
+ raise TypeError, "DSL Error: missing @#{opts.instance} for %s##{name}" % self.class.name
99
+ @#{opts.instance}.respond_to?(:[]) or
100
+ raise TypeError, "DSL Error: expected @#{opts.instance}[] is implemented (%s##{name})" % self.class.name
101
+ @#{opts.instance}[:#{ name }] || self.class.#{ name }
102
+ end
103
+ EOS
104
+ else
105
+ raise TypeError, "DSL Error: :instance should be true or Symbol, but got `%s' class" % opts.instance.class
106
+ end
107
+
108
+ instance_eval <<-EOS
109
+ def #{name}(*args, &block)
110
+ dsl_accessor_reader("#{name}", *args, &block)
111
+ end
112
+ def #{name}=(*args, &block)
113
+ dsl_accessor_writer("#{name}", *args, &block)
114
+ end
115
+ EOS
116
+ end
117
+ end
@@ -0,0 +1,41 @@
1
+ require 'blankslate'
2
+
3
+ module DslAccessor
4
+ module AutoDeclare
5
+ class DefineClassMethod < BasicObject
6
+ def initialize(context, &block)
7
+ @context = context
8
+ instance_eval(&block)
9
+ end
10
+
11
+ private
12
+ def method_missing(name, *args, &block)
13
+ if args.empty? and block
14
+ meta_class = (class << @context; self; end)
15
+ meta_class.class_eval{ define_method(name, &block) }
16
+ else
17
+ @context.__send__(name, *args, &block)
18
+ end
19
+ end
20
+ end
21
+
22
+ class DefineInstanceMethod < BasicObject
23
+ def initialize(klass, &block)
24
+ @klass = klass
25
+ instance_eval(&block)
26
+ end
27
+
28
+ private
29
+ def method_missing(name, *args, &block)
30
+ if args.empty? and block
31
+ @klass.class_eval{ define_method(name, &block) }
32
+ else
33
+ raise NameError, "undefined local variable or method `#{name}'"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+
41
+ __END__
@@ -0,0 +1,60 @@
1
+ module DslAccessor
2
+ module Stores
3
+ module Basic
4
+ # testing
5
+ def dsl_accessor_attributes
6
+ @dsl_accessor_attributes ||= {}
7
+ end
8
+
9
+ def dsl_accessor_key?(key)
10
+ dsl_accessor_attributes.has_key?(key)
11
+ end
12
+
13
+ def dsl_accessor_get(key)
14
+ dsl_accessor_attributes[key]
15
+ end
16
+
17
+ def dsl_accessor_set(key, val)
18
+ dsl_accessor_attributes[key] = val
19
+ end
20
+ end
21
+
22
+ module Inherit
23
+ # testing
24
+ def dsl_accessor_attributes
25
+ @dsl_accessor_attributes ||= {}
26
+ end
27
+
28
+ def dsl_accessor_key?(key)
29
+ dsl_accessor_attributes.has_key?(key)
30
+ end
31
+
32
+ def dsl_accessor_get(key)
33
+ if dsl_accessor_key?(key)
34
+ dsl_accessor_attributes[key]
35
+ else
36
+ superclass ? superclass.dsl_accessor_get(key) : nil
37
+ end
38
+ end
39
+
40
+ def dsl_accessor_set(key, val)
41
+ dsl_accessor_attributes[key] = val
42
+ end
43
+ end
44
+
45
+ module InheritableAttributes
46
+ # testing
47
+ def dsl_accessor_key?(key)
48
+ inheritable_attributes.has_key?(key)
49
+ end
50
+
51
+ def dsl_accessor_get(key)
52
+ read_inheritable_attribute(key)
53
+ end
54
+
55
+ def dsl_accessor_set(key, val)
56
+ write_inheritable_attribute(key, val)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,4 @@
1
+ module DslAccessor
2
+ VERSION = "0.4.2"
3
+ end
4
+
@@ -0,0 +1,56 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe DslAccessor do
4
+ it "class should provide 'dsl_accessor'" do
5
+ Class.new.should respond_to(:dsl_accessor)
6
+ end
7
+ end
8
+
9
+ describe "dsl_accessor(:foo)" do
10
+ before do
11
+ @klass = new_class { dsl_accessor :foo }
12
+ end
13
+
14
+ it "should provide 'foo' method" do
15
+ @klass.should respond_to(:foo)
16
+ end
17
+
18
+ it "should accept nil for default value" do
19
+ @klass.foo.should == nil
20
+ end
21
+
22
+ it "should provide 'foo=' method" do
23
+ @klass.should respond_to(:foo=)
24
+ end
25
+
26
+ it "#foo= should raise ArgumentError" do
27
+ lambda { @klass.send(:foo=) }.should raise_error(ArgumentError)
28
+ end
29
+
30
+ it "#foo=(1) should not raise ArgumentError" do
31
+ lambda { @klass.foo = 1 }.should_not raise_error(ArgumentError)
32
+ end
33
+
34
+ it "#foo=(1) should set :foo to 1" do
35
+ @klass.foo = 1
36
+ @klass.foo.should == 1
37
+ end
38
+
39
+ it "#foo=(1, 2) should raise ArgumentError" do
40
+ lambda { @klass.send(:foo=,1,2) }.should raise_error(ArgumentError)
41
+ end
42
+ end
43
+
44
+ describe "dsl_accessor(:foo, 1)" do
45
+ before do
46
+ @klass = new_class { dsl_accessor :foo, 1 }
47
+ end
48
+
49
+ it "should provide 'foo' method" do
50
+ @klass.should respond_to(:foo)
51
+ end
52
+
53
+ it "should accept 1 for default value" do
54
+ @klass.foo.should == 1
55
+ end
56
+ end
@@ -0,0 +1,123 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe DslAccessor do
4
+ before do
5
+ Object.send(:remove_const, :Foo) if Object.const_defined?(:Foo)
6
+ Foo = Class.new
7
+ end
8
+
9
+ def dsl_accessor(*args, &block)
10
+ Foo.dsl_accessor(*args, &block)
11
+ end
12
+
13
+ ######################################################################
14
+ ### Class Methods
15
+
16
+ describe "dsl_accessor(&block)" do
17
+ context " should raise NameError when" do
18
+ def dsl_accessor(*args, &block)
19
+ lambda { super }.should raise_error(NameError)
20
+ end
21
+
22
+ it "foo" do
23
+ dsl_accessor { foo }
24
+ end
25
+
26
+ it "foo(1)" do
27
+ dsl_accessor { foo(1) }
28
+ end
29
+
30
+ it "foo(1,2)" do
31
+ dsl_accessor { foo(1,2) }
32
+ end
33
+
34
+ it "foo(1) {}" do
35
+ dsl_accessor { foo(1) {} }
36
+ end
37
+ end
38
+
39
+ context " should define class method 'foo' when" do
40
+ def dsl_accessor(*args, &block)
41
+ super
42
+ Foo.should respond_to(:foo)
43
+ end
44
+
45
+ it "foo {}" do
46
+ dsl_accessor { foo {} }
47
+ end
48
+ end
49
+
50
+ it "should overwrite existing class methods such as 'name'" do
51
+ Foo.dsl_accessor {
52
+ name { 1 }
53
+ }
54
+ Foo.name.should == 1
55
+ end
56
+
57
+ it "should invoke the method in valid context" do
58
+ Foo.should_receive(:bar) { 2 }
59
+ dsl_accessor { foo { bar } }
60
+ Foo.foo.should == 2
61
+ end
62
+ end
63
+
64
+ ######################################################################
65
+ ### Instance Methods
66
+
67
+ describe "dsl_accessor(:instance, &block)" do
68
+ context " should raise NameError when" do
69
+ def dsl_accessor(*args, &block)
70
+ lambda { super }.should raise_error(NameError)
71
+ end
72
+
73
+ it "foo" do
74
+ dsl_accessor(:instance) { foo }
75
+ end
76
+
77
+ it "foo(1)" do
78
+ dsl_accessor(:instance) { foo(1) }
79
+ end
80
+
81
+ it "foo(1,2)" do
82
+ dsl_accessor(:instance) { foo(1,2) }
83
+ end
84
+
85
+ it "foo(1) {}" do
86
+ dsl_accessor(:instance) { foo(1) {} }
87
+ end
88
+ end
89
+
90
+ context " should define instance method 'foo' when" do
91
+ def dsl_accessor(*args, &block)
92
+ super
93
+ Foo.new.should respond_to(:foo)
94
+ end
95
+
96
+ it "foo {}" do
97
+ dsl_accessor(:instance) { foo {} }
98
+ end
99
+ end
100
+
101
+ it "should define instance method" do
102
+ Foo.dsl_accessor(:instance) {
103
+ foo { 'xxx' }
104
+ }
105
+ Foo.new.foo.should == 'xxx'
106
+ end
107
+
108
+ it "should orverwrite existed instance methods even if those are important like 'object_id'" do
109
+ Foo.new.object_id.should be_kind_of(Integer)
110
+ Foo.dsl_accessor(:instance) {
111
+ object_id { 'xxx' }
112
+ }
113
+ Foo.new.object_id.should == 'xxx'
114
+ end
115
+
116
+ it "should invoke the method in valid context" do
117
+ Foo.any_instance.should_receive(:bar) { 2 }
118
+ dsl_accessor(:instance) { foo { bar } }
119
+ Foo.new.foo.should == 2
120
+ end
121
+ end
122
+ end
123
+
@@ -0,0 +1,39 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe DslAccessor do
4
+ it "should duplicate blank array automatically" do
5
+ k1 = Class.new
6
+
7
+ array = []
8
+ k1.dsl_accessor :foo, array
9
+
10
+ k1.foo.should == array
11
+ k1.foo.should_not equal(array)
12
+ end
13
+
14
+ it "should duplicate blank hash automatically" do
15
+ k1 = Class.new
16
+
17
+ hash = {}
18
+ k1.dsl_accessor :foo, :default=>hash
19
+
20
+ k1.foo.should == hash
21
+ k1.foo.should_not equal(hash)
22
+ end
23
+
24
+ it "should call the method when symbol given" do
25
+ k1 = Class.new
26
+ def k1.construct
27
+ 1
28
+ end
29
+ k1.dsl_accessor :foo, :default=>:construct
30
+
31
+ k1.foo.should == 1
32
+ end
33
+
34
+ it "should call it when proc given" do
35
+ k1 = Class.new
36
+ k1.dsl_accessor :foo, :default=>proc{1}
37
+ k1.foo.should == 1
38
+ end
39
+ end
@@ -0,0 +1,48 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe DslAccessor do
4
+ # | foo | bar | baz | qux | quux |
5
+ # Bottom | * | * | o | o | |
6
+ # Middle | | o | | + | o |
7
+ # Top | + | | + | o | o |
8
+ #
9
+ # *) dsl_accessor :foo
10
+ # o) dsl_accessor :foo, 'val'
11
+ # +) foo 'val'
12
+
13
+ class Bottom
14
+ dsl_accessor :foo
15
+ dsl_accessor :bar
16
+ dsl_accessor :baz, 'baz1'
17
+ dsl_accessor :qux, 'qux1'
18
+ end
19
+
20
+ class Middle < Bottom
21
+ dsl_accessor :bar, 'bar2'
22
+ qux 'qux2'
23
+ dsl_accessor :quux, 'quux2'
24
+ end
25
+
26
+ class Top < Middle
27
+ foo 'foo3'
28
+ baz 'baz3'
29
+ dsl_accessor :qux , 'qux3'
30
+ dsl_accessor :quux, 'quux3'
31
+ end
32
+
33
+ it "should define accessor methods" do
34
+ Bottom.foo.should == nil
35
+ Bottom.bar.should == nil
36
+ Bottom.baz.should == 'baz1'
37
+ Bottom.qux.should == 'qux1'
38
+ lambda { Bottom.quux }.should raise_error(NameError)
39
+ end
40
+
41
+ it "should inherit value" do
42
+ Middle.foo.should == nil
43
+ Middle.bar.should == 'bar2'
44
+ Middle.baz.should == 'baz1'
45
+ Middle.qux.should == 'qux2'
46
+ Middle.quux.should == 'quux2'
47
+ end
48
+ end
@@ -0,0 +1,51 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe "dsl_accessor(:foo, :instance=>true)" do
4
+ before do
5
+ klass = Class.new
6
+ klass.dsl_accessor :foo, :instance=>true
7
+ @klass = klass
8
+ end
9
+
10
+ it "should provide instance method 'foo'" do
11
+ @klass.new.should respond_to(:foo)
12
+ end
13
+
14
+ it "should delegate instance method to class method about reader" do
15
+ @klass.foo 1
16
+ @klass.new.foo.should == 1
17
+ end
18
+ end
19
+
20
+ describe "dsl_accessor(:foo, :instance=>:opts)" do
21
+ before do
22
+ klass = Class.new
23
+ klass.dsl_accessor :foo, :instance=>:opts
24
+ @klass = klass
25
+ @obj = @klass.new
26
+ end
27
+
28
+ it "should raise error when @opts is not set" do
29
+ lambda {
30
+ @obj.foo
31
+ }.should raise_error(/missing @opts/)
32
+ end
33
+
34
+ it "should raise error when @opts is present but not responds to []" do
35
+ @obj.instance_eval "@opts = true"
36
+ lambda {
37
+ @obj.foo
38
+ }.should raise_error(/expected @opts\[\]/)
39
+ end
40
+
41
+ it "should read value from @opts first" do
42
+ @obj.instance_eval "@opts = {:foo=>2}"
43
+ @obj.foo.should == 2
44
+ end
45
+
46
+ it "should read value from class when @opts value is blank" do
47
+ @klass.foo 1
48
+ @obj.instance_eval "@opts = {}"
49
+ @obj.foo.should == 1
50
+ end
51
+ end
@@ -0,0 +1,22 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe Module do
4
+ it "should provide 'dsl_accessor'" do
5
+ Module.new.should respond_to(:dsl_accessor)
6
+ end
7
+
8
+ describe "#dsl_accessor(:foo, 1)" do
9
+ subject {
10
+ mod = Module.new
11
+ mod.dsl_accessor :foo, 1
12
+ mod
13
+ }
14
+ # default value
15
+ its(:foo) { should == 1}
16
+
17
+ it "foo(2) should update value to 2" do
18
+ subject.foo 2
19
+ subject.foo.should == 2
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe "dsl_accessor :foo" do
4
+ before do
5
+ @klass = new_class { dsl_accessor :foo }
6
+ end
7
+
8
+ it "should accept foo(1)" do
9
+ @klass.foo 1
10
+ @klass.foo.should == 1
11
+ end
12
+
13
+ it "should reject foo(1, &block)" do
14
+ lambda {
15
+ @klass.foo(2) { 3 }
16
+ }.should raise_error(ArgumentError)
17
+ end
18
+
19
+ it "should accept foo(&block)" do
20
+ @klass.foo { 4 }
21
+ @klass.foo.should be_kind_of(Proc)
22
+ @klass.foo.call.should == 4
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ require "rubygems"
2
+ require "rspec"
3
+
4
+ require File.dirname(__FILE__) + "/../lib/dsl_accessor"
5
+
6
+ ######################################################################
7
+ ### Helper methods
8
+
9
+ def new_class(&block)
10
+ Class.new(&block)
11
+ end
@@ -0,0 +1,35 @@
1
+ require File.join( File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe DslAccessor do
4
+ it "should call writer" do
5
+ klass = new_class
6
+
7
+ klass.dsl_accessor :key, "bar", :writer=>proc{|value| "[#{value}]"}
8
+ klass.key.should == "[bar]"
9
+
10
+ klass.key 'foo'
11
+ klass.key.should == "[foo]"
12
+ end
13
+
14
+ it "should call writer even if no default values given" do
15
+ klass = new_class
16
+
17
+ klass.dsl_accessor :key, :writer=>proc{|value| "[#{value}]"}
18
+ klass.key.should == "[]"
19
+
20
+ klass.key 'foo'
21
+ klass.key.should == "[foo]"
22
+ end
23
+
24
+ it "should call the method when symbol given" do
25
+ klass = new_class
26
+
27
+ klass.dsl_accessor :key, :default=>"foo", :writer=>:labelize
28
+ def klass.labelize(val)
29
+ "[#{val}]"
30
+ end
31
+
32
+ klass.key.should == "[foo]"
33
+ end
34
+
35
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :dsl_accessor do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: genki-dsl_accessor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - genki
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: optionize
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.1.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: This plugin gives hybrid accessor class methods to classes by DSL like
47
+ definition
48
+ email:
49
+ - genki@s21g.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - Gemfile
55
+ - MIT-LICENSE
56
+ - README
57
+ - Rakefile
58
+ - core_ext/module/delegation.rb
59
+ - dsl_accessor.gemspec
60
+ - lib/dsl_accessor.rb
61
+ - lib/dsl_accessor/accessor.rb
62
+ - lib/dsl_accessor/auto_declare.rb
63
+ - lib/dsl_accessor/stores.rb
64
+ - lib/dsl_accessor/version.rb
65
+ - spec/accessor_spec.rb
66
+ - spec/auto_declared_spec.rb
67
+ - spec/default_spec.rb
68
+ - spec/inherit_spec.rb
69
+ - spec/instance_spec.rb
70
+ - spec/module_spec.rb
71
+ - spec/setter_spec.rb
72
+ - spec/spec_helper.rb
73
+ - spec/writer_spec.rb
74
+ - tasks/dsl_accessor_tasks.rake
75
+ homepage: https://github.com/genki/dsl_accessor
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project: dsl_accessor
95
+ rubygems_version: 1.8.24
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: This plugin gives hybrid accessor class methods to classes by DSL like definition
99
+ test_files:
100
+ - spec/accessor_spec.rb
101
+ - spec/auto_declared_spec.rb
102
+ - spec/default_spec.rb
103
+ - spec/inherit_spec.rb
104
+ - spec/instance_spec.rb
105
+ - spec/module_spec.rb
106
+ - spec/setter_spec.rb
107
+ - spec/spec_helper.rb
108
+ - spec/writer_spec.rb