dsl_maker 0.1.0 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 99ee47867d6b31ded1c99a54a01aa793a61592f3
4
- data.tar.gz: 5e11770909897a850465398142d13ea52e533f54
3
+ metadata.gz: ee345a0ba8d01c3d91f40755ba0c18ac527c57eb
4
+ data.tar.gz: 515dae62c2f621d2ae8c12df517231d209e460a8
5
5
  SHA512:
6
- metadata.gz: 9106d1d87a86d23e4eccb86b39d4a972e413cf3ce1dd7c469f36889de039f4162494da84abc0a5247312f61e64ca2c1b5b33e5ac694e3428d8640771d8de6504
7
- data.tar.gz: 9e1084f369c61cc4029b90ff76a555f17203b3c52913d5aaca1168b93f7725d1b8f2696170b12047e12fb936a7dc24acb0cf8e2ad24688493249a3b17db03b7e
6
+ metadata.gz: 0983a84dbed2c14f98b7f1d8d2ce6c76bfe59a24f4c74c604f52e8877e830286523de6e4cf3f7747d354e313235689e84dd1fb1bebdb2f3472645740b3217b97
7
+ data.tar.gz: b59a9f5d5e9095e5fcddbdbbdc0df8a43488a3d9d93ab2a58dcf435f681dd1fff97c5a6ec415352464ad2c7703931b767d5b08e3c54c49bda4b5aef636e57d9e
data/Changes CHANGED
@@ -1,5 +1,10 @@
1
1
  Revision history for DSL::Maker (ordered by revision number).
2
2
 
3
+ 0.1.1 Aug 24 2015
4
+ - add_helper() no longer pollutes DSL::Maker::Base
5
+ - Add remove_helper() and has_helper?()
6
+ - Rename is_dsl() to is_dsl?()
7
+
3
8
  0.1.0 Aug 11 2015
4
9
  BREAKING CHANGE:
5
10
  - parse_dsl() and execute_dsl() now always return an array, even if there is
data/lib/dsl/maker.rb CHANGED
@@ -89,7 +89,7 @@ class DSL::Maker
89
89
  ArrayOf = Class.new do
90
90
  def self.[](type)
91
91
  raise "Cannot make an array of an alias" if DSL::Maker.is_alias(type)
92
- raise "Unknown type provided to ArrayOf" unless @@types.has_key?(type) || DSL::Maker.is_dsl(type)
92
+ raise "Unknown type provided to ArrayOf" unless @@types.has_key?(type) || DSL::Maker.is_dsl?(type)
93
93
  @@arrays[type] ||= ArrayType.new(type)
94
94
  end
95
95
  end
@@ -99,12 +99,9 @@ class DSL::Maker
99
99
 
100
100
  # Parse the DSL provided in the parameter.
101
101
  #
102
- # @note If the DSL contains multiple entrypoints, then this will return an
103
- # Array. This is desirable.
104
- #
105
102
  # @param dsl [String] The DSL to be parsed by this class.
106
103
  #
107
- # @return [Object] Whatever is returned by the block defined in this class.
104
+ # @return [Array] Whatever is returned by the block defined in this class.
108
105
  def self.parse_dsl(dsl=nil)
109
106
  raise 'Must call add_entrypoint before parse_dsl' unless @klass
110
107
  raise 'String required for parse_dsl' unless dsl.instance_of? String
@@ -114,12 +111,9 @@ class DSL::Maker
114
111
 
115
112
  # Execute the DSL provided in the block.
116
113
  #
117
- # @note If the DSL contains multiple entrypoints, then this will return an
118
- # Array. This is desirable.
119
- #
120
114
  # @param &block [Block] The DSL to be executed by this class.
121
115
  #
122
- # @return [Object] Whatever is returned by &block
116
+ # @return [Array] Whatever is returned by the block defined in this class.
123
117
  def self.execute_dsl(&block)
124
118
  raise 'Must call add_entrypoint before execute_dsl' unless @klass
125
119
  raise 'Block required for execute_dsl' unless block_given?
@@ -140,7 +134,7 @@ class DSL::Maker
140
134
  # and ___set() available for your use. These are aliases to
141
135
  # instance_variable_get and instance_variable_set, respectively. Please read the
142
136
  # coercions provided for you in this source file as examples.
143
- #
137
+ #
144
138
  # @return nil
145
139
  def self.add_type(type, &block)
146
140
  raise "Block required for add_type" unless block_given?
@@ -166,7 +160,7 @@ class DSL::Maker
166
160
  def self.generate_dsl(args={}, &defn_block)
167
161
  raise 'Block required for generate_dsl' unless block_given?
168
162
 
169
- dsl_class = Class.new(DSL::Maker::Base) do
163
+ dsl_class = Class.new(base_class) do
170
164
  include DSL::Maker::Boolean
171
165
 
172
166
  class << self
@@ -199,7 +193,7 @@ class DSL::Maker
199
193
  # @param name [String] the name of the entrypoint
200
194
  # @param args [Hash] the elements of the DSL block (passed to generate_dsl)
201
195
  # @param defn_block [Proc] what is executed once the DSL block is parsed.
202
- #
196
+ #
203
197
  # @return [Class] The class that implements this level's DSL definition.
204
198
  def self.add_entrypoint(name, args={}, &defn_block)
205
199
  symname = name.to_sym
@@ -208,7 +202,7 @@ class DSL::Maker
208
202
  raise "'#{name.to_s}' is already an entrypoint"
209
203
  end
210
204
 
211
- if is_dsl(args)
205
+ if is_dsl?(args)
212
206
  dsl_class = args
213
207
  else
214
208
  # Without defn_block, there's no way to give back the result of the
@@ -218,7 +212,7 @@ class DSL::Maker
218
212
  raise "Block required for add_entrypoint" unless block_given?
219
213
  dsl_class = generate_dsl(args, &defn_block)
220
214
  end
221
-
215
+
222
216
  if @klass
223
217
  build_dsl_element(@klass, symname, dsl_class)
224
218
  else
@@ -241,7 +235,7 @@ class DSL::Maker
241
235
  # This returns the DSL corresponding to the entrypoint's name.
242
236
  #
243
237
  # @param name [String] the name of the entrypoint
244
- #
238
+ #
245
239
  # @return [Class] The class that implements this name's DSL definition.
246
240
  def self.entrypoint(name)
247
241
  unless is_entrypoint(name)
@@ -257,22 +251,46 @@ class DSL::Maker
257
251
  #
258
252
  # @param name [String] the name of the helper
259
253
  # @param &block [Block] The function to be executed when the helper is called.
260
- #
254
+ #
261
255
  # @return nil
262
256
  def self.add_helper(name, &block)
263
257
  raise "Block required for add_helper" unless block_given?
264
258
 
265
- if DSL::Maker::Base.new.respond_to? name.to_sym
259
+ if has_helper? name
266
260
  raise "'#{name.to_s}' is already a helper"
267
261
  end
268
262
 
269
- DSL::Maker::Base.class_eval do
263
+ base_class.class_eval do
270
264
  define_method(name.to_sym, &block)
271
265
  end
272
266
 
273
267
  return
274
268
  end
275
269
 
270
+ # This removes a helper function that's been added with #add_helper
271
+ #
272
+ # @param name [String] the name of the helper
273
+ #
274
+ # @return nil
275
+ def self.remove_helper(name)
276
+ unless has_helper? name
277
+ raise "'#{name.to_s}' is not a helper"
278
+ end
279
+
280
+ base_class.class_eval do
281
+ remove_method(name.to_sym)
282
+ end
283
+ end
284
+
285
+ # This returns if the helper has been added with #add_helper
286
+ #
287
+ # @param name [String] the name of the helper
288
+ #
289
+ # @return Boolean
290
+ def self.has_helper?(name)
291
+ base_class.method_defined?(name.to_sym)
292
+ end
293
+
276
294
  # This adds a verification that's executed after the DSL is finished parsing.
277
295
  #
278
296
  # The verification will be called with the value(s) returned by the entrypoint's
@@ -289,7 +307,7 @@ class DSL::Maker
289
307
  #
290
308
  # @param name [String] the name of the entrypoint to add a verification to
291
309
  # @param &block [Block] The function to be executed when verifications execute
292
- #
310
+ #
293
311
  # @return nil
294
312
  def self.add_verification(name, &block)
295
313
  raise "Block required for add_verification" unless block_given?
@@ -332,7 +350,7 @@ class DSL::Maker
332
350
  instance_exec('@' + name.to_s, *args, &@@types[type])
333
351
  end
334
352
  end
335
- elsif is_dsl(type)
353
+ elsif is_dsl?(type)
336
354
  as_attr = '@' + name.to_s
337
355
  klass.class_eval do
338
356
  define_method(name.to_sym) do |*args, &dsl_block|
@@ -374,7 +392,7 @@ class DSL::Maker
374
392
  ___set(as_attr, rv = []) unless rv
375
393
 
376
394
  if dsl_block
377
- # This code is copy-pasted from the is_dsl() section above. Figure out
395
+ # This code is copy-pasted from the is_dsl?() section above. Figure out
378
396
  # how to hoist this code into something reusable. But, we don't need
379
397
  # the parent_class section (do we?)
380
398
  obj = type.base_type.new
@@ -419,13 +437,28 @@ class DSL::Maker
419
437
  return @accumulator
420
438
  end
421
439
 
422
- def self.is_dsl(proto)
440
+ def self.is_dsl?(proto)
423
441
  proto.is_a?(Class) && proto.ancestors.include?(DSL::Maker::Base)
424
442
  end
425
443
 
426
444
  def self.is_entrypoint(name)
427
445
  @entrypoints && @entrypoints.has_key?(name.to_sym)
428
446
  end
447
+
448
+ def self.base_class
449
+ # This is the only time we *know* that the :default helper doesn't exist yet.
450
+ unless @base_class
451
+ @base_class = Class.new(DSL::Maker::Base)
452
+ add_helper(:default) do |method_name, args, position=0|
453
+ method = method_name.to_sym
454
+ if args.length >= (position + 1) && !self.send(method)
455
+ self.send(method, args[position])
456
+ end
457
+ return
458
+ end
459
+ end
460
+ @base_class
461
+ end
429
462
  end
430
463
 
431
464
  # These are the default setups
@@ -447,18 +480,3 @@ DSL::Maker.add_type(DSL::Maker::Boolean) do |attr, *args|
447
480
  # Ensure that the default nil also returns as false.
448
481
  !!___get(attr)
449
482
  end
450
-
451
- # A helper method for handling defaults from args easily.
452
- #
453
- # @param method_name [String] The name of the attribute being defaulted.
454
- # @param args [Array] The arguments provided to the block.
455
- # @param position [Integer] The index in args to work with, default 0.
456
- #
457
- # @return nil
458
- DSL::Maker.add_helper(:default) do |method_name, args, position=0|
459
- method = method_name.to_sym
460
- if args.length >= (position + 1) && !self.send(method)
461
- self.send(method, args[position])
462
- end
463
- return
464
- end
@@ -1,6 +1,6 @@
1
1
  module DSL
2
2
  class Maker
3
3
  # The current version of this library
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
6
6
  end
data/spec/error_spec.rb CHANGED
@@ -125,29 +125,41 @@ describe "DSL::Maker validation" do
125
125
  end
126
126
 
127
127
  describe "for helpers" do
128
- it "rejects a helper without a block" do
129
- dsl_class = Class.new(DSL::Maker)
128
+ context "#add_helper" do
129
+ it "rejects a helper without a block" do
130
+ dsl_class = Class.new(DSL::Maker)
130
131
 
131
- expect {
132
- dsl_class.add_helper(:x)
133
- }.to raise_error('Block required for add_helper')
134
- end
132
+ expect {
133
+ dsl_class.add_helper(:x)
134
+ }.to raise_error('Block required for add_helper')
135
+ end
135
136
 
136
- it "rejects the helper name default" do
137
- dsl_class = Class.new(DSL::Maker)
137
+ it "rejects the helper name default" do
138
+ dsl_class = Class.new(DSL::Maker)
138
139
 
139
- expect {
140
- dsl_class.add_helper(:default) {}
141
- }.to raise_error("'default' is already a helper")
140
+ expect {
141
+ dsl_class.add_helper(:default) {}
142
+ }.to raise_error("'default' is already a helper")
143
+ end
144
+
145
+ it "rejects a helper name already in use" do
146
+ dsl_class = Class.new(DSL::Maker)
147
+ dsl_class.add_helper(:x) {}
148
+
149
+ expect {
150
+ dsl_class.add_helper(:x) {}
151
+ }.to raise_error("'x' is already a helper")
152
+ end
142
153
  end
143
154
 
144
- it "rejects a helper name already in use" do
145
- dsl_class = Class.new(DSL::Maker)
146
- dsl_class.add_helper(:x) {}
155
+ context "#remove_helper" do
156
+ it "rejects a helper name not already in use" do
157
+ dsl_class = Class.new(DSL::Maker)
147
158
 
148
- expect {
149
- dsl_class.add_helper(:x) {}
150
- }.to raise_error("'x' is already a helper")
159
+ expect {
160
+ dsl_class.remove_helper(:x)
161
+ }.to raise_error("'x' is not a helper")
162
+ end
151
163
  end
152
164
  end
153
165
 
data/spec/helper_spec.rb CHANGED
@@ -1,60 +1,84 @@
1
1
  # This uses a DSL that also provides a set of useful helpers.
2
2
  #
3
- describe "A DSL with helpers" do
4
- it "can add a helper that's useful" do
5
- dsl_class = Class.new(DSL::Maker) do
6
- add_entrypoint(:car, {
7
- :maker => String,
8
- }) do
9
- Structs::Car.new(maker)
10
- end
3
+ describe 'A DSL with helpers' do
4
+ context '#add_helper' do
5
+ it "can add a helper that's useful" do
6
+ dsl_class = Class.new(DSL::Maker) do
7
+ add_entrypoint(:car, {
8
+ :maker => String,
9
+ }) do
10
+ Structs::Car.new(maker)
11
+ end
11
12
 
12
- add_helper(:transform) do |name|
13
- name.upcase
13
+ add_helper(:transform) do |name|
14
+ name.upcase
15
+ end
14
16
  end
17
+
18
+ car = dsl_class.parse_dsl("
19
+ car {
20
+ maker transform('Honda')
21
+ }
22
+ ")[0]
23
+ expect(car).to be_instance_of(Structs::Car)
24
+ expect(car.maker).to eq('HONDA')
15
25
  end
16
26
 
17
- car = dsl_class.parse_dsl("
18
- car {
19
- maker transform('Honda')
20
- }
21
- ")[0]
22
- expect(car).to be_instance_of(Structs::Car)
23
- expect(car.maker).to eq('HONDA')
27
+ it 'adds the helper to every level' do
28
+ dsl_class = Class.new(DSL::Maker) do
29
+ add_entrypoint(:car, {
30
+ :maker => String,
31
+ :wheel => generate_dsl({
32
+ :maker => String,
33
+ }) do
34
+ Structs::Wheel.new(maker)
35
+ end
36
+ }) do
37
+ Structs::Car.new(maker, wheel)
38
+ end
39
+
40
+ add_helper(:transform) do |name|
41
+ name.upcase
42
+ end
43
+ end
44
+
45
+ car = dsl_class.parse_dsl("
46
+ car {
47
+ maker 'Honda'
48
+ wheel {
49
+ maker transform('goodyear')
50
+ }
51
+ }
52
+ ")[0]
53
+ expect(car).to be_instance_of(Structs::Car)
54
+ expect(car.maker).to eq('Honda')
55
+ expect(car.wheel).to be_instance_of(Structs::Wheel)
56
+ expect(car.wheel.maker).to eq('GOODYEAR')
57
+ end
24
58
  end
25
59
 
26
- # TODO: There is a wart here. We cannot call add_helper() twice in our tests
27
- # for the same name even in different specs. The specs should be able to reset
28
- # the class, but I'm not sure how.
29
- it "adds the helper to every level" do
30
- dsl_class = Class.new(DSL::Maker) do
31
- add_entrypoint(:car, {
32
- :maker => String,
33
- :wheel => generate_dsl({
60
+ context '#remove_helper' do
61
+ it 'can remove a helper' do
62
+ dsl_class = Class.new(DSL::Maker) do
63
+ add_entrypoint(:car, {
34
64
  :maker => String,
35
65
  }) do
36
- Structs::Wheel.new(maker)
66
+ Structs::Car.new(maker)
37
67
  end
38
- }) do
39
- Structs::Car.new(maker, wheel)
40
- end
41
68
 
42
- add_helper(:transform2) do |name|
43
- name.upcase
69
+ remove_helper(:default)
70
+ add_helper(:default) do |name|
71
+ name.upcase
72
+ end
44
73
  end
45
- end
46
74
 
47
- car = dsl_class.parse_dsl("
48
- car {
49
- maker 'Honda'
50
- wheel {
51
- maker transform2('goodyear')
75
+ car = dsl_class.parse_dsl("
76
+ car {
77
+ maker default('Honda')
52
78
  }
53
- }
54
- ")[0]
55
- expect(car).to be_instance_of(Structs::Car)
56
- expect(car.maker).to eq('Honda')
57
- expect(car.wheel).to be_instance_of(Structs::Wheel)
58
- expect(car.wheel.maker).to eq('GOODYEAR')
79
+ ")[0]
80
+ expect(car).to be_instance_of(Structs::Car)
81
+ expect(car.maker).to eq('HONDA')
82
+ end
59
83
  end
60
84
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dsl_maker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Kinyon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-11 00:00:00.000000000 Z
11
+ date: 2015-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docile