dsel 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +0 -0
  3. data/Gemfile +15 -0
  4. data/LICENSE.md +23 -0
  5. data/README.md +113 -0
  6. data/Rakefile +6 -0
  7. data/dsel.gemspec +22 -0
  8. data/lib/dsel/api/generator.rb +285 -0
  9. data/lib/dsel/api/node.rb +241 -0
  10. data/lib/dsel/api.rb +8 -0
  11. data/lib/dsel/dsl/mixins/environment/ivar_explorer.rb +34 -0
  12. data/lib/dsel/dsl/nodes/api/environment.rb +49 -0
  13. data/lib/dsel/dsl/nodes/api.rb +18 -0
  14. data/lib/dsel/dsl/nodes/api_builder/environment.rb +56 -0
  15. data/lib/dsel/dsl/nodes/api_builder.rb +71 -0
  16. data/lib/dsel/dsl/nodes/base/environment.rb +50 -0
  17. data/lib/dsel/dsl/nodes/base.rb +110 -0
  18. data/lib/dsel/dsl/nodes/direct/environment.rb +14 -0
  19. data/lib/dsel/dsl/nodes/direct.rb +75 -0
  20. data/lib/dsel/dsl/nodes/proxy/environment.rb +41 -0
  21. data/lib/dsel/dsl/nodes/proxy.rb +20 -0
  22. data/lib/dsel/dsl.rb +10 -0
  23. data/lib/dsel/node.rb +42 -0
  24. data/lib/dsel/ruby/object.rb +53 -0
  25. data/lib/dsel/version.rb +3 -0
  26. data/lib/dsel.rb +10 -0
  27. data/spec/dsel/api/generator_spec.rb +402 -0
  28. data/spec/dsel/api/node_spec.rb +328 -0
  29. data/spec/dsel/dsel_spec.rb +63 -0
  30. data/spec/dsel/dsl/nodes/api/environment.rb +208 -0
  31. data/spec/dsel/dsl/nodes/api_builder/environment_spec.rb +91 -0
  32. data/spec/dsel/dsl/nodes/api_builder_spec.rb +148 -0
  33. data/spec/dsel/dsl/nodes/api_spec.rb +15 -0
  34. data/spec/dsel/dsl/nodes/direct/environment_spec.rb +14 -0
  35. data/spec/dsel/dsl/nodes/direct_spec.rb +43 -0
  36. data/spec/dsel/dsl/nodes/proxy/environment_spec.rb +56 -0
  37. data/spec/dsel/dsl/nodes/proxy_spec.rb +11 -0
  38. data/spec/spec_helper.rb +22 -0
  39. data/spec/support/factories/clean_api_spec.rb +6 -0
  40. data/spec/support/fixtures/mock_api.rb +4 -0
  41. data/spec/support/helpers/paths.rb +19 -0
  42. data/spec/support/lib/factory.rb +107 -0
  43. data/spec/support/shared/dsl/nodes/base/environment.rb +104 -0
  44. data/spec/support/shared/dsl/nodes/base.rb +171 -0
  45. data/spec/support/shared/node.rb +70 -0
  46. metadata +108 -0
@@ -0,0 +1,328 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DSeL::API::Node do
4
+ it_should_behave_like DSeL::Node
5
+
6
+ subject { Factory[:clean_api_spec] }
7
+ let(:other) { Factory[:clean_api_spec] }
8
+ let(:another) { Factory[:clean_api_spec] }
9
+ let(:api) { subject.new( Object.new ) }
10
+
11
+ describe '.define' do
12
+ it "delegates to #{DSeL::API::Generator}#define_definers" do
13
+ types = [:stuff, :stuff2]
14
+ expect(DSeL::API::Generator).to receive(:define_definers).with( subject, *types )
15
+
16
+ subject.define *types
17
+ end
18
+
19
+ context 'when a description has been set' do
20
+ context 'and more than 1 type is given' do
21
+ it 'raises ArgumentError' do
22
+ subject.describe 'Stuff'
23
+
24
+ expect do
25
+ subject.define :stuff, :stuff2
26
+ end.to raise_error ArgumentError
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'when options have been set' do
32
+ context 'and more than 1 type is given' do
33
+ it 'raises ArgumentError' do
34
+ subject.configure []
35
+
36
+ expect do
37
+ subject.define :stuff, :stuff2
38
+ end.to raise_error ArgumentError
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '.describe' do
45
+ let(:description) { 'Blah' }
46
+
47
+ it 'sets a description for the following definer' do
48
+ subject.describe description
49
+ subject.define :on
50
+
51
+ expect(subject.definers).to eq [{ type: :on, description: description, method: :def_on}]
52
+ end
53
+
54
+ it 'sets a description for the following call handler' do
55
+ subject.define :on
56
+
57
+ subject.describe description
58
+ subject.def_on( :stuff ) {}
59
+
60
+ ch = subject.call_handlers.first
61
+ ch.delete :method
62
+ expect(ch).to eq( type: :on, description: description, object: :stuff)
63
+ end
64
+
65
+ it 'sets a description for the following child' do
66
+ subject.describe description
67
+ subject.push_child :blah, other
68
+
69
+ expect(subject.children).to eq(
70
+ blah: {
71
+ name: :blah,
72
+ node: other,
73
+ description: description
74
+ }
75
+ )
76
+ end
77
+ end
78
+
79
+ describe '.configure' do
80
+ let(:options) { { blah: :stuff } }
81
+
82
+ it 'sets a description for the following definer' do
83
+ subject.configure options
84
+ subject.define :on
85
+
86
+ expect(subject.definers).to eq [{ type: :on, options: [options], method: :def_on}]
87
+ end
88
+
89
+ it 'sets a description for the following call handler' do
90
+ subject.define :on
91
+
92
+ subject.configure options
93
+ subject.def_on( :stuff ) {}
94
+
95
+ ch = subject.call_handlers.first
96
+ ch.delete :method
97
+ expect(ch).to eq( type: :on, options: [options], object: :stuff)
98
+ end
99
+
100
+ it 'sets a description for the following child' do
101
+ subject.configure options
102
+ subject.push_child :blah, other
103
+
104
+ expect(subject.children).to eq(
105
+ blah: {
106
+ name: :blah,
107
+ node: other,
108
+ options: [options]
109
+ }
110
+ )
111
+ end
112
+ end
113
+
114
+ describe '.has_options?' do
115
+ context 'when options are available in the buffer' do
116
+ it 'returns true' do
117
+ subject.configure []
118
+ expect(subject).to have_options
119
+ end
120
+ end
121
+
122
+ context 'when options are not available in the buffer' do
123
+ it 'returns false' do
124
+ expect(subject).to_not have_options
125
+ end
126
+ end
127
+ end
128
+
129
+ describe '.has_description?' do
130
+ context 'when a description is available in the buffer' do
131
+ it 'returns true' do
132
+ subject.describe ''
133
+ expect(subject).to have_description
134
+ end
135
+ end
136
+
137
+ context 'when no description is available in the buffer' do
138
+ it 'returns false' do
139
+ expect(subject).to_not have_description
140
+ end
141
+ end
142
+ end
143
+
144
+ describe '.root' do
145
+ it 'returns the root node' do
146
+ subject.push_child :blah, other
147
+ other.push_child :another, another
148
+
149
+ expect(another.root).to be subject
150
+ end
151
+
152
+ context 'when .root?' do
153
+ it 'returns self' do
154
+ expect(subject.root).to be subject
155
+ end
156
+ end
157
+ end
158
+
159
+ describe '.parent' do
160
+ it 'returns the parent node' do
161
+ subject.push_child :blah, other
162
+ expect(other.parent).to be subject
163
+
164
+ other.push_child :another, another
165
+ expect(another.parent).to be other
166
+ end
167
+
168
+ context 'when .root?' do
169
+ it 'returns nil' do
170
+ expect(subject.parent).to be_nil
171
+ end
172
+ end
173
+ end
174
+
175
+ describe '.has_call_handler?' do
176
+ context 'when there is a call handler' do
177
+ it 'returns true' do
178
+ subject.define :on
179
+
180
+ subject.def_on {}
181
+ expect( subject ).to have_call_handler :on
182
+
183
+ subject.def_on( :stuff ) {}
184
+ expect( subject ).to have_call_handler :on, :stuff
185
+ end
186
+ end
187
+
188
+ context 'when there is no such call handler' do
189
+ it 'returns false' do
190
+ expect( subject ).to_not have_call_handler :blah
191
+
192
+ subject.define :on
193
+
194
+ expect( subject ).to_not have_call_handler :on
195
+ expect( subject ).to_not have_call_handler :on, :stuff
196
+ end
197
+ end
198
+ end
199
+
200
+ describe '.root?' do
201
+ context 'when there is no parent' do
202
+ it 'returns true' do
203
+ expect(subject).to be_root
204
+ end
205
+ end
206
+
207
+ context 'when there is a parent' do
208
+ it 'returns false' do
209
+ subject.push_child :blah, other
210
+ expect(other).to_not be_root
211
+ end
212
+ end
213
+ end
214
+
215
+ describe '.child?' do
216
+ context 'when there is no parent' do
217
+ it 'returns false' do
218
+ expect(subject).to_not be_child
219
+ end
220
+ end
221
+
222
+ context 'when there is a parent' do
223
+ it 'returns true' do
224
+ subject.push_child :blah, other
225
+ expect(other).to be_child
226
+ end
227
+ end
228
+ end
229
+
230
+ describe '.push_child' do
231
+ before do
232
+ subject.push_child :blah, other, s
233
+ end
234
+ let(:s) { nil }
235
+
236
+ it 'sets the given node as a child' do
237
+ expect(subject.children).to eq(
238
+ blah: {
239
+ name: :blah,
240
+ node: other
241
+ }
242
+ )
243
+ end
244
+
245
+ it 'creates an instance method for access' do
246
+ expect(api.blah).to be_kind_of other
247
+ expect(api.blah).to be api.blah
248
+ end
249
+
250
+ context 'when given a subject' do
251
+ context 'Symbol' do
252
+ let(:s) { :hash }
253
+
254
+ it 'sends it to the parent subject and uses the result as a subject' do
255
+ expect(api.blah.subject).to be api.subject.hash
256
+ end
257
+ end
258
+
259
+ context '#call' do
260
+ let(:s) { proc { |o| o.hash } }
261
+
262
+ it 'uses the result as a subject' do
263
+ expect(api.blah.subject).to be api.subject.hash
264
+ end
265
+ end
266
+
267
+ context 'other' do
268
+ it 'raises ArgumentError' do
269
+ expect do
270
+ subject.push_child :another, another, ''
271
+ end.to raise_error ArgumentError
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ describe '.push_children' do
278
+ it 'delegates to .push_child' do
279
+ expect(subject).to receive(:push_child).with(:blah, other)
280
+ expect(subject).to receive(:push_child).with(:another, another)
281
+
282
+ subject.push_children(
283
+ blah: other,
284
+ another: another
285
+ )
286
+ end
287
+ end
288
+
289
+ describe '.tree' do
290
+ it 'returns the API tree' do
291
+ subject.push_child :blah, other
292
+ other.push_child :another, another
293
+
294
+ tree = {
295
+ definers: [],
296
+ call_handlers: [],
297
+ children: {
298
+ :blah => {
299
+ :name => :blah,
300
+ :node => other,
301
+ :definers => [],
302
+ :call_handlers => [],
303
+ :children => {
304
+ another: {
305
+ :name => :another,
306
+ :node => another,
307
+ :definers => [],
308
+ :call_handlers => [],
309
+ :children => {}
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+
316
+ expect(another.tree). to eq tree
317
+ end
318
+ end
319
+
320
+ describe '.branch' do
321
+ it "returns the node's branch" do
322
+ subject.push_child :blah, other
323
+ other.push_child :another, another
324
+
325
+ expect(subject.branch). to eq other.tree
326
+ end
327
+ end
328
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DSeL do
4
+
5
+ it 'has a version number' do
6
+ expect(DSeL::VERSION).not_to be nil
7
+ end
8
+
9
+ describe 'examples/' do
10
+ let(:examples_dir) { examples_path }
11
+
12
+ describe 'api/' do
13
+ let(:api_dir) { "#{examples_dir}/api/" }
14
+
15
+ describe 'my_api' do
16
+ before do
17
+ require "#{api_dir}/my_api"
18
+ end
19
+
20
+ describe 'my_api_dsl' do
21
+ it 'works' do
22
+ expect do
23
+ MyAPI.run "#{api_dir}/my_api_dsl.rb"
24
+ end.to_not raise_error
25
+ end
26
+ end
27
+
28
+ describe 'my_api_ruby' do
29
+ it 'works' do
30
+ expect do
31
+ require "#{api_dir}/my_api_ruby"
32
+ end.to_not raise_error
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ describe 'dsl/' do
39
+ let(:dsl_dir) { "#{examples_dir}/dsl/" }
40
+
41
+ before do
42
+ require "#{dsl_dir}/object"
43
+ end
44
+
45
+ describe 'proxy' do
46
+ it 'works' do
47
+ expect do
48
+ require "#{dsl_dir}/proxy"
49
+ end.to_not raise_error
50
+ end
51
+ end
52
+
53
+ describe 'direct' do
54
+ it 'works' do
55
+ expect do
56
+ require "#{dsl_dir}/direct"
57
+ end.to_not raise_error
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,208 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DSeL::DSL::Nodes::API::Environment do
4
+ include_examples DSeL::DSL::Nodes::Base::Environment
5
+
6
+ let(:api_spec) { Factory[:clean_api_spec] }
7
+ let(:other_api_spec) { Factory[:clean_api_spec] }
8
+ let(:node_context) { api_spec.new }
9
+
10
+ let(:other_node_context) { api_spec.new }
11
+ let(:another_node_context) { api_spec.new }
12
+
13
+ context 'when the API node has children' do
14
+ before do
15
+ api_spec.push_child :other_api_spec, other_api_spec
16
+ end
17
+
18
+ it 'creates DSL helpers for them' do
19
+ child = node.run { Other_api_spec { real_self } }
20
+ expect(child).to be node_context.other_api_spec
21
+ end
22
+ end
23
+
24
+ describe '#also' do
25
+ let(:calls) { [] }
26
+
27
+ context 'when repeating a catch-all' do
28
+ before do
29
+ api_spec.define :on
30
+
31
+ c = calls
32
+ api_spec.def_on do |*args|
33
+ c << [:on, args]
34
+ end
35
+ end
36
+
37
+ context 'that had no arguments' do
38
+ it 'does not send any arguments' do
39
+ node.run do
40
+ on
41
+ also
42
+ end
43
+
44
+ expect(calls).to eq [[:on, []], [:on, []]]
45
+ end
46
+
47
+ context 'with new arguments' do
48
+ it 'sends the new arguments' do
49
+ node.run do
50
+ on
51
+ also :stuff
52
+ end
53
+
54
+ expect(calls).to eq [[:on, []], [:on, [:stuff]]]
55
+ end
56
+ end
57
+ end
58
+
59
+ context 'that had arguments' do
60
+ it 'does not send any arguments' do
61
+ node.run do
62
+ on :stuff
63
+ also
64
+ end
65
+
66
+ expect(calls).to eq [[:on, [:stuff]], [:on, []]]
67
+ end
68
+
69
+ context 'with new arguments' do
70
+ it 'sends the new arguments' do
71
+ node.run do
72
+ on :stuff
73
+ also :stuff2
74
+ end
75
+
76
+ expect(calls).to eq [[:on, [:stuff]], [:on, [:stuff2]]]
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ context 'when repeating an object call' do
83
+ before do
84
+ api_spec.define :on
85
+
86
+ c = calls
87
+
88
+ api_spec.def_on :stuff do |*args|
89
+ c << [:stuff, args]
90
+ end
91
+
92
+ api_spec.def_on :other_stuff do |*args|
93
+ c << [:other_stuff, args]
94
+ end
95
+ end
96
+
97
+ context 'with a specified object' do
98
+ it 'changes the call handler' do
99
+ node.run do
100
+ on :stuff
101
+ also :other_stuff
102
+ end
103
+
104
+ expect(calls).to eq [[:stuff, []], [:other_stuff, []]]
105
+ end
106
+
107
+ context 'that had no arguments' do
108
+ it 'does not send any arguments' do
109
+ node.run do
110
+ on :stuff
111
+ also :other_stuff
112
+ end
113
+
114
+ expect(calls).to eq [[:stuff, []], [:other_stuff, []]]
115
+ end
116
+
117
+ context 'with new arguments' do
118
+ it 'sends the new arguments' do
119
+ node.run do
120
+ on :stuff
121
+ also :other_stuff, :arg
122
+ end
123
+
124
+ expect(calls).to eq [[:stuff, []], [:other_stuff, [:arg]]]
125
+ end
126
+ end
127
+ end
128
+
129
+ context 'that had arguments' do
130
+ it 'does not send any arguments' do
131
+ node.run do
132
+ on :stuff, :arg
133
+ also :other_stuff
134
+ end
135
+
136
+ expect(calls).to eq [[:stuff, [:arg]], [:other_stuff, []]]
137
+ end
138
+
139
+ context 'with new arguments' do
140
+ it 'sends the new arguments' do
141
+ node.run do
142
+ on :stuff
143
+ also :other_stuff, :arg
144
+ end
145
+
146
+ expect(calls).to eq [[:stuff, []], [:other_stuff, [:arg]]]
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ context 'without an object' do
153
+ it 'uses the previous call handler' do
154
+ node.run do
155
+ on :stuff
156
+ also :stuff2
157
+ end
158
+
159
+ expect(calls).to eq [[:stuff, []], [:stuff, [:stuff2]]]
160
+ end
161
+
162
+ context 'that had no arguments' do
163
+ it 'does not send any arguments' do
164
+ node.run do
165
+ on :stuff
166
+ also
167
+ end
168
+
169
+ expect(calls).to eq [[:stuff, []], [:stuff, []]]
170
+ end
171
+
172
+ context 'with new arguments' do
173
+ it 'sends the new arguments' do
174
+ node.run do
175
+ on :stuff
176
+ also :arg
177
+ end
178
+
179
+ expect(calls).to eq [[:stuff, []], [:stuff, [:arg]]]
180
+ end
181
+ end
182
+ end
183
+
184
+ context 'that had arguments' do
185
+ it 'does not send any arguments' do
186
+ node.run do
187
+ on :stuff, :arg
188
+ also
189
+ end
190
+
191
+ expect(calls).to eq [[:stuff, [:arg]], [:stuff, []]]
192
+ end
193
+
194
+ context 'with new arguments' do
195
+ it 'sends the new arguments' do
196
+ node.run do
197
+ on :stuff
198
+ also :arg
199
+ end
200
+
201
+ expect(calls).to eq [[:stuff, []], [:stuff, [:arg]]]
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DSeL::DSL::Nodes::APIBuilder::Environment do
4
+ include_examples DSeL::DSL::Nodes::Base::Environment
5
+
6
+ let(:node_context) { Factory[:clean_api_spec] }
7
+ let(:other_node_context) { Factory[:clean_api_spec] }
8
+ let(:another_node_context) { Factory[:clean_api_spec] }
9
+
10
+ subject do
11
+ def node.cleanup_environment
12
+ end
13
+
14
+ node.run{}
15
+ node.environment
16
+ end
17
+
18
+ let(:script) do
19
+ <<RUBY
20
+ define :on
21
+ RUBY
22
+ end
23
+ let(:filename) do
24
+ 'script.rb'
25
+ end
26
+ let(:file) do
27
+ File.open "#{Dir.tmpdir}/#{filename}", 'w' do |f|
28
+ f.write script
29
+ f.flush
30
+ f.path
31
+ end
32
+ end
33
+
34
+ describe '#import' do
35
+ it 'imports a file' do
36
+ expect(subject.definers).to be_empty
37
+ subject.import file
38
+ expect(subject.definers).to eq [{ type: :on, method: :def_on}]
39
+ end
40
+
41
+ context 'without extension' do
42
+ let(:filename) do
43
+ 'script'
44
+ end
45
+
46
+ it 'assumes .rb' do
47
+ expect(subject.definers).to be_empty
48
+ subject.import file
49
+ expect(subject.definers).to eq [{ type: :on, method: :def_on}]
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '#import_many' do
55
+ it 'imports globs' do
56
+ expect(subject.definers).to be_empty
57
+ subject.import_many "#{Dir.tmpdir}/scr*pt"
58
+ expect(subject.definers).to eq [{ type: :on, method: :def_on}]
59
+ end
60
+ end
61
+
62
+ describe '#import_relative' do
63
+ it 'imports a file'
64
+
65
+ context 'without extension' do
66
+ let(:filename) do
67
+ 'script'
68
+ end
69
+
70
+ it 'assumes .rb'
71
+ end
72
+ end
73
+
74
+ describe '#import_relative_many' do
75
+ it 'imports relative globs'
76
+ end
77
+
78
+ describe '#child' do
79
+ it 'adds a child node' do
80
+ subject.child :child, :Child do
81
+ end
82
+
83
+ expect(subject.children).to eq(
84
+ child: {
85
+ name: :child,
86
+ node: subject.const_get( :Child )
87
+ }
88
+ )
89
+ end
90
+ end
91
+ end