dockly-util 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,29 +22,64 @@ module Dockly::Util::DSL
22
22
  end
23
23
  private :dsl_attribute
24
24
 
25
- def dsl_class_attribute(name, klass)
25
+ def dsl_class_attribute(name, klass, options={})
26
26
  unless klass.ancestors.include?(Dockly::Util::DSL)
27
- raise "#{self.class}.dsl_class_attribute requires a class that includes DSL"
28
- end
29
- define_method(name) do |sym = nil, &block|
30
- new_value = case
31
- when !block.nil? && !sym.nil? then klass.new!(:name => sym, &block)
32
- when block.nil? then klass.instances[sym]
33
- when sym.nil? then klass.new!(:name => :"#{self.name}_#{klass}", &block)
34
- end
35
- instance_variable_set(:"@#{name}", new_value) unless new_value.nil?
36
- instance_variable_get(:"@#{name}")
27
+ raise "#{self}.dsl_class_attribute requires a class that includes DSL"
37
28
  end
29
+ type = options.delete(:type) || Object
30
+ generated_related_name = :"#{self.underscore(self.demodulize(self.to_s))}"
31
+ related_name = options.delete(:related_name) || generated_related_name
32
+ define_forward_relation(name, related_name, self, klass, type)
33
+ define_reverse_relation(related_name, name, klass, self)
38
34
  end
39
35
  private :dsl_class_attribute
40
36
 
37
+ def define_forward_relation(name, related_name, current_class, klass, type)
38
+ current_class.instance_eval do
39
+ define_method(name) do |sym = nil, &block|
40
+ new_value = case
41
+ when !block.nil? && !sym.nil? then klass.new!(:name => sym, &block)
42
+ when block.nil? then klass.instances[sym]
43
+ when sym.nil? then klass.new!(:name => :"#{self.name}_#{klass}", &block)
44
+ end
45
+ unless new_value.nil?
46
+ if type.ancestors.include? Array
47
+ val = instance_variable_get(:"@#{name}") || []
48
+ instance_variable_set(:"@#{name}", val + [new_value])
49
+ else
50
+ instance_variable_set(:"@#{name}", new_value)
51
+ end
52
+ new_value.instance_variable_set(
53
+ :"@#{related_name}",
54
+ self
55
+ )
56
+ end
57
+ instance_variable_get(:"@#{name}")
58
+ end
59
+ end
60
+ end
61
+ private :define_forward_relation
62
+
63
+ def define_reverse_relation(name, related_name, current_class, klass)
64
+ current_class.instance_eval do
65
+ define_method(name) do
66
+ instance_variable_get(:"@#{name}")
67
+ end
68
+ end
69
+ end
70
+ private :define_reverse_relation
71
+
41
72
  def default_value(name, val = nil)
42
73
  default_values[name] = block_given? ? yield : val
43
74
  end
44
75
  private :default_value
45
76
 
46
77
  def default_values
47
- @default_values ||= {}
78
+ @default_values ||= if self.superclass.respond_to?(:default_values)
79
+ self.superclass.default_values
80
+ else
81
+ {}
82
+ end
48
83
  end
49
84
 
50
85
  def instances
@@ -59,6 +94,17 @@ module Dockly::Util::DSL
59
94
  end
60
95
  end
61
96
 
97
+ def underscore(camel_cased_word)
98
+ word = camel_cased_word.to_s.dup
99
+ word.gsub!('::', '/')
100
+ word.gsub!(/(?:([A-Za-z\d])|^)(#{/(?=a)b/})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
101
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
102
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
103
+ word.tr!("-", "_")
104
+ word.downcase!
105
+ word
106
+ end
107
+
62
108
  def generate_unique_name
63
109
  name = nil
64
110
  (0..(1.0 / 0.0)).each do |n|
@@ -1,5 +1,5 @@
1
1
  module Dockly
2
2
  module Util
3
- VERSION = '0.0.5'
3
+ VERSION = '0.0.6'
4
4
  end
5
5
  end
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+
3
+ class IncludedClass
4
+ include Dockly::Util::DSL
5
+
6
+ dsl_attribute :ocean
7
+ end
8
+
9
+ class TestClass
10
+ include Dockly::Util::DSL
11
+
12
+ dsl_attribute :chips
13
+ dsl_class_attribute :meta, IncludedClass
14
+ end
15
+
16
+ class ArrayClass
17
+ include Dockly::Util::DSL
18
+
19
+ dsl_class_attribute :attr, IncludedClass, type: Array
20
+ end
21
+
22
+ describe Dockly::Util::DSL do
23
+ let(:included_class) { IncludedClass }
24
+ let(:test_class) { TestClass }
25
+ let(:array_class) { ArrayClass }
26
+
27
+ let(:test_instance) { test_class.new!(:name => 'Tony') }
28
+ let(:array_instance) { array_class.new! }
29
+
30
+ describe '.dsl_attribute' do
31
+ it 'defines a method for each name given' do
32
+ test_instance.should respond_to :chips
33
+ end
34
+
35
+ context 'the defined method(s)' do
36
+ context 'with 0 arguments' do
37
+ let(:test_val) { 'lays' }
38
+ before { test_instance.instance_variable_set(:@chips, test_val) }
39
+
40
+ it 'returns the value of the instance variable with a matching name' do
41
+ test_instance.chips.should == test_val
42
+ end
43
+ end
44
+
45
+ context 'with one argument' do
46
+ it 'sets the corresponding instance variable to the passed-in value' do
47
+ expect { test_instance.chips('bbq') }
48
+ .to change { test_instance.instance_variable_get(:@chips) }
49
+ .to 'bbq'
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '.dsl_class_attribute' do
56
+ context 'when the sceond argument is not a DSL' do
57
+ it 'raises an error' do
58
+ expect do
59
+ Class.new do
60
+ include Dockly::Util::DSL
61
+
62
+ dsl_class_attribute :test, Array
63
+ end
64
+ end.to raise_error
65
+ end
66
+ end
67
+
68
+ context 'when the second argument is a DSL' do
69
+ it 'defines a new method with the name of the first argument' do
70
+ test_instance.should respond_to :meta
71
+ array_instance.should respond_to :attr
72
+ end
73
+
74
+ it 'defines a new method on the DSL class with the name of the current class' do
75
+ included_class.new.should respond_to :test_class
76
+ included_class.new.should respond_to :array_class
77
+ end
78
+
79
+ context 'the method' do
80
+ context 'for a regular class attribute' do
81
+ let(:meta) { test_instance.instance_variable_get(:@meta) }
82
+
83
+ context 'when a symbol is given' do
84
+ context 'and a block is given' do
85
+ before { test_instance.meta(:yolo) { ocean 'Indian' } }
86
+
87
+ it 'creates a new instance of the specified Class with the name set' do
88
+ meta.name.should == :yolo
89
+ meta.ocean.should == 'Indian'
90
+ end
91
+ end
92
+
93
+ context 'and a block is not given' do
94
+ before { included_class.new!(:name => :test_name) { ocean 'Pacific' } }
95
+
96
+ it 'looks up the instance in its Class\'s .instances hash' do
97
+ test_instance.meta(:test_name).ocean.should == 'Pacific'
98
+ end
99
+ end
100
+ end
101
+
102
+ context 'when a symbol is not given' do
103
+ context 'and a block is given' do
104
+ before { test_instance.meta { ocean 'Atlantic' } }
105
+
106
+ it 'creates a new instance of the specified Class' do
107
+ meta.ocean.should == 'Atlantic'
108
+ end
109
+
110
+ it 'generates a name' do
111
+ meta.name.should == :"#{test_instance.name}_#{meta.class}"
112
+ end
113
+ end
114
+
115
+ context 'and a block is not given' do
116
+ before { test_instance.meta(:test) { ocean 'Artic' } }
117
+
118
+ it 'returns the corresponding instance variable' do
119
+ test_instance.meta.should == meta
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ context 'for an array class attribute' do
126
+ let(:attr) { array_instance.instance_variable_get(:@attr) }
127
+
128
+ context 'when a symbol is given' do
129
+ context 'and a block is given' do
130
+ before { array_instance.attr(:yolo) { ocean 'Indian' } }
131
+
132
+ it 'creates a new instance of the specified Class with the name set' do
133
+ expect(attr.length).to be == 1
134
+ expect(attr.first.ocean).to be == 'Indian'
135
+ end
136
+ end
137
+
138
+ context 'and a block is not given' do
139
+ before { included_class.new!(:name => :test_name) { ocean 'Pacific' } }
140
+
141
+ it 'looks up the instance in its Class\'s .instances hash' do
142
+ expect(array_instance.attr(:test_name).first.ocean).to be == 'Pacific'
143
+ end
144
+ end
145
+ end
146
+
147
+ context 'when a symbol is not given' do
148
+ context 'and a block is given' do
149
+ before { array_instance.attr { ocean 'Atlantic' } }
150
+
151
+ it 'creates a new instance of the specified Class' do
152
+ attr.first.ocean.should == 'Atlantic'
153
+ end
154
+
155
+ it 'generates a name' do
156
+ attr.first.name.should == :"#{array_instance.name}_#{IncludedClass.to_s}"
157
+ end
158
+ end
159
+
160
+ context 'and a block is not given' do
161
+ before { array_instance.attr(:test) { ocean 'Artic' } }
162
+
163
+ it 'returns the corresponding instance variable' do
164
+ array_instance.attr.should == attr
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ describe '#ensure_present!' do
174
+ context 'when at least one of the symbols is nil' do
175
+ it 'raises an error' do
176
+ expect { test_instance.send(:ensure_present!, :meta) }.to raise_error
177
+ end
178
+ end
179
+
180
+ context 'when each symbol is present' do
181
+ it 'does nothing' do
182
+ expect { test_instance.send(:ensure_present!, :name) }.to_not raise_error
183
+ end
184
+ end
185
+ end
186
+
187
+ describe '.default_value' do
188
+ context 'when a block is given' do
189
+ it 'calls the block and adds it to he default_values hash' do
190
+ test_class.send(:default_value, :meta) { included_class.new!(:name => :joey) }
191
+ test_class.default_values[:meta].name.should == :joey
192
+ end
193
+ end
194
+
195
+ context 'when a value is given' do
196
+ it 'adds the pair to the default_values hash' do
197
+ test_class.send(:default_value, :chips, 'Cool Ranch')
198
+ test_class.default_values[:chips].should == 'Cool Ranch'
199
+ end
200
+ end
201
+ end
202
+
203
+ describe '#initialize' do
204
+ context 'when a block is given' do
205
+ it 'is instance evaluated' do
206
+ test_class.new! { name :timmy }.name.should == :timmy
207
+ end
208
+ end
209
+
210
+ context 'when a hash is given' do
211
+ it 'sends each key value pair to the object as a message' do
212
+ test_class.new!(:name => :tommy).name.should == :tommy
213
+ end
214
+ end
215
+
216
+ context 'when there is a name' do
217
+ it 'adds the current instance to the class\'s instances hash' do
218
+ test_class.instances[:jillian].should be_nil
219
+ test_class.new! { name :jillian }
220
+ test_class.instances[:jillian].name.should == :jillian
221
+ end
222
+ end
223
+ end
224
+ end
File without changes
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
3
 
4
4
  require 'rspec'
5
+ require 'pry'
5
6
  require 'dockly/util'
6
7
 
7
8
  RSpec.configure do |config|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dockly-util
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-07 00:00:00.000000000 Z
12
+ date: 2013-11-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -98,8 +98,8 @@ files:
98
98
  - lib/dockly/util/dsl.rb
99
99
  - lib/dockly/util/logger.rb
100
100
  - lib/dockly/util/version.rb
101
- - spec/dockl/util/dsl_spec.rb
102
- - spec/dockl/util/logger_spec.rb
101
+ - spec/dockly/util/dsl_spec.rb
102
+ - spec/dockly/util/logger_spec.rb
103
103
  - spec/spec_helper.rb
104
104
  homepage: https://github.com/swipely/dockly-util
105
105
  licenses:
@@ -127,7 +127,7 @@ signing_key:
127
127
  specification_version: 3
128
128
  summary: DSL made easy
129
129
  test_files:
130
- - spec/dockl/util/dsl_spec.rb
131
- - spec/dockl/util/logger_spec.rb
130
+ - spec/dockly/util/dsl_spec.rb
131
+ - spec/dockly/util/logger_spec.rb
132
132
  - spec/spec_helper.rb
133
133
  has_rdoc:
@@ -1,171 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Dockly::Util::DSL do
4
- let(:included_class) do
5
- Class.new do
6
- include Dockly::Util::DSL
7
-
8
- dsl_attribute :ocean
9
- end
10
- end
11
-
12
- let(:test_class) do
13
- klass = included_class
14
- Class.new do
15
- include Dockly::Util::DSL
16
-
17
- dsl_attribute :chips
18
- dsl_class_attribute :meta, klass
19
- end
20
- end
21
-
22
- subject { test_class.new!(:name => 'Tony') }
23
-
24
- describe '.dsl_attribute' do
25
- it 'defines a method for each name given' do
26
- subject.should respond_to :chips
27
- end
28
-
29
- context 'the defined method(s)' do
30
- context 'with 0 arguments' do
31
- let(:test_val) { 'lays' }
32
- before { subject.instance_variable_set(:@chips, test_val) }
33
-
34
- it 'returns the value of the instance variable with a matching name' do
35
- subject.chips.should == test_val
36
- end
37
- end
38
-
39
- context 'with one argument' do
40
- it 'sets the corresponding instance variable to the passed-in value' do
41
- expect { subject.chips('bbq') }
42
- .to change { subject.instance_variable_get(:@chips) }
43
- .to 'bbq'
44
- end
45
- end
46
- end
47
- end
48
-
49
- describe '.dsl_class_attribute' do
50
- context 'when the sceond argument is not a DSL' do
51
- it 'raises an error' do
52
- expect do
53
- Class.new do
54
- include Dockly::Util::DSL
55
-
56
- dsl_class_attribute :test, Array
57
- end
58
- end.to raise_error
59
- end
60
- end
61
-
62
- context 'when the second argument is a DSL' do
63
- it 'defines a new method with the name of the first argument' do
64
- subject.should respond_to :meta
65
- end
66
-
67
- context 'the method' do
68
- let(:meta) { subject.instance_variable_get(:@meta) }
69
-
70
- context 'when a symbol is given' do
71
- context 'and a block is given' do
72
- before { subject.meta(:yolo) { ocean 'Indian' } }
73
-
74
- it 'creates a new instance of the specified Class with the name set' do
75
- meta.name.should == :yolo
76
- meta.ocean.should == 'Indian'
77
- end
78
- end
79
-
80
- context 'and a block is not given' do
81
- before { included_class.new!(:name => :test_name) { ocean 'Pacific' } }
82
-
83
- it 'looks up the instance in its Class\'s .instances hash' do
84
- subject.meta(:test_name).ocean.should == 'Pacific'
85
- end
86
- end
87
- end
88
-
89
- context 'when a symbol is not given' do
90
- context 'and a block is given' do
91
- before { subject.meta { ocean 'Atlantic' } }
92
-
93
- it 'creates a new instance of the specified Class' do
94
- meta.ocean.should == 'Atlantic'
95
- end
96
-
97
- it 'generates a name' do
98
- meta.name.should == :"#{subject.name}_#{meta.class}"
99
- end
100
- end
101
-
102
- context 'and a block is not given' do
103
- before { subject.meta(:test) { ocean 'Artic' } }
104
-
105
- it 'returns the corresponding instance variable' do
106
- subject.meta.should == meta
107
- end
108
- end
109
- end
110
- end
111
- end
112
- end
113
-
114
- describe '#ensure_present!' do
115
- context 'when at least one of the symbols is nil' do
116
- it 'raises an error' do
117
- expect { subject.send(:ensure_present!, :meta) }.to raise_error
118
- end
119
- end
120
-
121
- context 'when each symbol is present' do
122
- it 'does nothing' do
123
- expect { subject.send(:ensure_present!, :name) }.to_not raise_error
124
- end
125
- end
126
- end
127
-
128
- describe '.default_value' do
129
- context 'when a block is given' do
130
- it 'calls the block and adds it to he default_values hash' do
131
- test_class.send(:default_value, :meta) { included_class.new!(:name => :joey) }
132
- test_class.default_values[:meta].name.should == :joey
133
- end
134
- end
135
-
136
- context 'when a value is given' do
137
- it 'adds the pair to the default_values hash' do
138
- test_class.send(:default_value, :chips, 'Cool Ranch')
139
- test_class.default_values[:chips].should == 'Cool Ranch'
140
- end
141
- end
142
- end
143
-
144
- describe '#initialize' do
145
- context 'when a block is given' do
146
- it 'is instance evaluated' do
147
- test_class.new! { name :timmy }.name.should == :timmy
148
- end
149
- end
150
-
151
- context 'when a hash is given' do
152
- it 'sends each key value pair to the object as a message' do
153
- test_class.new!(:name => :tommy).name.should == :tommy
154
- end
155
- end
156
-
157
- context 'when there is no name' do
158
- it 'raises an error' do
159
- expect { test_class.new! { chips 'Tortilla' } }.to raise_error
160
- end
161
- end
162
-
163
- context 'when there is a name' do
164
- it 'adds the current instance to the class\'s instances hash' do
165
- test_class.instances[:jillian].should be_nil
166
- test_class.new! { name :jillian }
167
- test_class.instances[:jillian].name.should == :jillian
168
- end
169
- end
170
- end
171
- end