dsel 0.1.0

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.
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