dsl_maker 0.0.4 → 0.0.5

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: ff32adb37883c0c6466af73eac18c78e0315cffd
4
- data.tar.gz: ebaaa08053e1c7d1a3066c3a3ec18cebf685a10b
3
+ metadata.gz: cf937996460904dce3266547aab1e117ee498e8d
4
+ data.tar.gz: 85796fbba9b301299057952af7b5b72bda58d4cc
5
5
  SHA512:
6
- metadata.gz: 237aef00aa5afa13e8d5cd39a72ee339e43de1988426305f1af0183b15a242d971de0a3398bae3a5817f1a2cc9f96a8c64fb36888b6617571b5f7c656757c8f6
7
- data.tar.gz: 3274e9f900246bac32bc9dbec107e2120544d8241a4109857b79ae4a2d33ec147dd69a832d00392a351a95af015f4f3756110641a6855e3ebe2f98b5c3d05247
6
+ metadata.gz: 96fce7def349ca81bebe71ea969f6f7af69d242409a4ffc8c39c5b9bc2cfbd0e9952a903191f02ebe154ba4740c801c439948713d11c0c4fb47d540e8c36a835
7
+ data.tar.gz: 8673a94d49a4acb702937b099de6a3c4b20d52b896c4e8a25e16ff59fce3f6c7a1fdbb5abcb536cd24bc7f3a62119134f1b890d6ee4335f254ee59d07532f30c
data/Changes CHANGED
@@ -1,5 +1,11 @@
1
1
  Revision history for DSL::Maker (ordered by revision number).
2
2
 
3
+ 0.0.5 Jul 30 2015
4
+ - Added missing YaRDOC for new features in 0.0.4
5
+ - Added add_coercion() to allow the user to define new coercions for use when
6
+ creating their DSL.
7
+ - Eat our own dogfood vis-a-vis helpers and coercions.
8
+
3
9
  0.0.4 Jul 29 2015
4
10
  - Added add_helper() to allow the user to define new helper methods for use
5
11
  within the DSL.
data/README.md CHANGED
@@ -300,6 +300,13 @@ This is normally called by `generate_dsl()` to actually construct the DSL elemen
300
300
  It is provided for you so that you can create recursive DSL definitions. Look at
301
301
  the tests in `spec/multi_level_spec.rb` for an example of this.
302
302
 
303
+ * `add_type(Object, Block)`
304
+
305
+ This is used to create type coercions that are used when defining your DSL. These
306
+ are treated at the same level as the default type coercions described below.
307
+
308
+ This creates global type coercions that are available to every DSL definition.
309
+
303
310
  * `add_helper(Symbol, Block)`
304
311
 
305
312
  This is used to create helper methods (similar to `default`, described below) that
@@ -316,15 +323,16 @@ In the case of multiple DSL entrypoints (for example, a normal Chef recipe),
316
323
  these methods will return an array with all the return values in the order they
317
324
  were encountered.
318
325
 
319
- ### Coercions
326
+ ### Type Coercions
320
327
 
321
- There are three defined coercions for use within `generate_dsl()`:
328
+ There are four pre-defined type coercions for use within `generate_dsl()`:
322
329
 
323
- * String - This takes any string.
330
+ * String - This takes whatever you give it and returns the string within it.
331
+ * Integer - This takes whatever you give it and returns the integer within it.
324
332
  * Boolean - This takes whatever you give it and returns the truthiness of it.
325
333
  * `generate_dsl()` - This descends into another level of DSL.
326
334
 
327
- You will be able to add your own coercions in a forthcoming version of DSL::Maker.
335
+ You can add additional type coercions using `add_type()` as described above.
328
336
 
329
337
  ### Helpers
330
338
 
@@ -335,7 +343,7 @@ There is one pre-defined helper.
335
343
  This takes a method name and the args provided to the block. It then ensures that
336
344
  the method defaults to the value in the args at the optional third argument.
337
345
 
338
- You can add additional helpers using `add_helper()` described above.
346
+ You can add additional helpers using `add_helper()` as described above.
339
347
 
340
348
  ## Installation
341
349
 
@@ -346,8 +354,6 @@ $ gem install dsl_maker
346
354
  ## TODO
347
355
 
348
356
  * Add support for Arrays
349
- * Add additional coercions (e.g., Number)
350
- * Allow you to add your own coercions
351
357
 
352
358
  ## Links
353
359
 
@@ -1,6 +1,6 @@
1
1
  module DSL
2
2
  class Maker
3
3
  # The current version of this library
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  end
6
6
  end
data/lib/dsl/maker.rb CHANGED
@@ -11,21 +11,6 @@ class DSL::Maker
11
11
 
12
12
  # 21 character method names are obscene. Make it easier to read.
13
13
  alias :___get :instance_variable_get
14
-
15
- # A helper method for handling defaults from args easily.
16
- #
17
- # @param method_name [String] The name of the attribute being defaulted.
18
- # @param args [Array] The arguments provided to the block.
19
- # @param position [Integer] The index in args to work with, default 0.
20
- #
21
- # @return nil
22
- def default(method_name, args, position=0)
23
- method = method_name.to_sym
24
- if args.length >= (position + 1) && !self.send(method)
25
- self.send(method, args[position])
26
- end
27
- return
28
- end
29
14
  end
30
15
 
31
16
  # This is a useful module that contains all the Boolean handling we need.
@@ -93,27 +78,52 @@ class DSL::Maker
93
78
 
94
79
  # FIXME: This may have to be changed when the elements can be altered because
95
80
  # it is global to the hierarchy. But, that may be desirable.
96
- @@dsl_elements = {
97
- String => ->(klass, name, type) {
98
- as_attr = '@' + name.to_s
99
- klass.class_eval do
100
- define_method(name.to_sym) do |*args|
101
- ___set(as_attr, args[0].to_s) unless args.empty?
102
- ___get(as_attr)
103
- end
104
- end
105
- },
106
- DSL::Maker::Boolean => ->(klass, name, type) {
81
+ @@types = {}
82
+
83
+ # This adds a type coercion that's used when creating the DSL.
84
+ #
85
+ # Note: These type coercions are global to all DSLs.
86
+ #
87
+ # @param type [Object] the name of the helper
88
+ # @param &block [Block] The function to be executed when the coercion is exercised.
89
+ #
90
+ # Your block will receive the following signature: |attr, *args| where 'attr' is
91
+ # the name of the attribute and *args are the arguments passed into your method.
92
+ # You are responsible for acting as a mutator. You have ___get() and ___set()
93
+ # available for your use. These are aliases to instance_variable_get and
94
+ # instance_variable_set, respectively. Please read the coercions provided for
95
+ # you in this source file.
96
+ #
97
+ # @return nil
98
+ def self.add_type(type, &block)
99
+ raise "Block required for add_type" unless block_given?
100
+ raise "'#{type}' is already a type coercion" if @@types.has_key? type
101
+
102
+ @@types[type] = ->(klass, name, type) {
107
103
  as_attr = '@' + name.to_s
108
104
  klass.class_eval do
109
105
  define_method(name.to_sym) do |*args|
110
- ___set(as_attr, Boolean.coerce(args[0])) unless args.empty?
111
- # Ensure that the default nil returns as false.
112
- !!___get(as_attr)
106
+ instance_exec(as_attr, *args, &block)
113
107
  end
114
108
  end
115
- },
116
- }
109
+ }
110
+
111
+ return
112
+ end
113
+
114
+ add_type(Integer) do |attr, *args|
115
+ ___set(attr, args[0].to_i) unless args.empty?
116
+ ___get(attr)
117
+ end
118
+ add_type(String) do |attr, *args|
119
+ ___set(attr, args[0].to_s) unless args.empty?
120
+ ___get(attr)
121
+ end
122
+ add_type(Boolean) do |attr, *args|
123
+ ___set(attr, Boolean.coerce(args[0])) unless args.empty?
124
+ # Ensure that the default nil also returns as false.
125
+ !!___get(attr)
126
+ end
117
127
 
118
128
  $is_dsl = lambda do |proto|
119
129
  proto.is_a?(Class) && proto.ancestors.include?(DSL::Maker::Base)
@@ -122,21 +132,22 @@ class DSL::Maker
122
132
  # Add a single element of a DSL to a class representing a level in a DSL.
123
133
  #
124
134
  # Each of the types represents a coercion - a guarantee and check of the value
125
- # in that name. The standard coercions are:
135
+ # in that name. The standard type coercions are:
126
136
  #
127
137
  # * String - whatever you give is returned.
138
+ # * Integer - the integer value of whatever you give is returned.
128
139
  # * Boolean - the truthiness of whatever you give is returned.
129
140
  # * generate_dsl() - this represents a new level of the DSL.
130
141
  #
131
142
  # @param klass [Class] The class representing this level in the DSL.
132
143
  # @param name [String] The name of the element we're working on.
133
144
  # @param type [Class] The type of this element we're working on.
134
- # This is the coercion spoken above.
145
+ # This is the type coercion spoken above.
135
146
  #
136
147
  # @return nil
137
148
  def self.build_dsl_element(klass, name, type)
138
- if @@dsl_elements.has_key?(type)
139
- @@dsl_elements[type].call(klass, name, type)
149
+ if @@types.has_key?(type)
150
+ @@types[type].call(klass, name, type)
140
151
  elsif $is_dsl.call(type)
141
152
  as_attr = '@' + name.to_s
142
153
  klass.class_eval do
@@ -221,8 +232,6 @@ class DSL::Maker
221
232
  raise "'#{name.to_s}' is already an entrypoint"
222
233
  end
223
234
 
224
- # FIXME: This is a wart. Really, we should be pulling out name, then
225
- # yielding to generate_dsl() in some fashion.
226
235
  if $is_dsl.call(args)
227
236
  dsl_class = args
228
237
  else
@@ -254,6 +263,14 @@ class DSL::Maker
254
263
  return @entrypoints[name.to_sym]
255
264
  end
256
265
 
266
+ # This adds a helper function that's accessible within the DSL.
267
+ #
268
+ # Note: These helpers are global to all DSLs.
269
+ #
270
+ # @param name [String] the name of the helper
271
+ # @param &block [Block] The function to be executed when the helper is called.
272
+ #
273
+ # @return nil
257
274
  def self.add_helper(name, &block)
258
275
  raise "Block required for add_helper" unless block_given?
259
276
 
@@ -264,5 +281,22 @@ class DSL::Maker
264
281
  DSL::Maker::Base.class_eval do
265
282
  define_method(name.to_sym, &block)
266
283
  end
284
+
285
+ return
286
+ end
287
+
288
+ # A helper method for handling defaults from args easily.
289
+ #
290
+ # @param method_name [String] The name of the attribute being defaulted.
291
+ # @param args [Array] The arguments provided to the block.
292
+ # @param position [Integer] The index in args to work with, default 0.
293
+ #
294
+ # @return nil
295
+ add_helper(:default) do |method_name, args, position=0|
296
+ method = method_name.to_sym
297
+ if args.length >= (position + 1) && !self.send(method)
298
+ self.send(method, args[position])
299
+ end
300
+ return
267
301
  end
268
302
  end
@@ -8,7 +8,7 @@ describe "Passing a class into generate_dsl" do
8
8
  it "can do it" do
9
9
  wheel_dsl = Class.new(DSL::Maker) do
10
10
  add_entrypoint(:wheel, {
11
- :size => String,
11
+ :size => Integer,
12
12
  :maker => String,
13
13
  }) do |*args|
14
14
  default(:maker, args, 0)
@@ -37,7 +37,7 @@ describe "Passing a class into generate_dsl" do
37
37
  expect(car.maker).to eq('honda')
38
38
  expect(car.wheel).to be_instance_of($Wheel)
39
39
  expect(car.wheel.maker).to eq('goodyear')
40
- expect(car.wheel.size).to eq('26')
40
+ expect(car.wheel.size).to eq(26)
41
41
  end
42
42
 
43
43
  # This ensures that if we create multiple entrypoints with the same name, they
@@ -45,7 +45,7 @@ describe "Passing a class into generate_dsl" do
45
45
  it "will not tramp on the entrypoints with the same name" do
46
46
  wheel_dsl = Class.new(DSL::Maker) do
47
47
  add_entrypoint(:wheel, {
48
- :size => String,
48
+ :size => Integer,
49
49
  :maker => String,
50
50
  }) do |*args|
51
51
  default(:maker, args, 0)
@@ -78,6 +78,6 @@ describe "Passing a class into generate_dsl" do
78
78
  expect(car.maker).to eq('honda')
79
79
  expect(car.wheel).to be_instance_of($Wheel)
80
80
  expect(car.wheel.maker).to eq('goodyear')
81
- expect(car.wheel.size).to eq('26')
81
+ expect(car.wheel.size).to eq(26)
82
82
  end
83
83
  end
data/spec/error_spec.rb CHANGED
@@ -1,14 +1,6 @@
1
1
  # This verifies the various error-handling situations.
2
2
 
3
3
  describe "DSL::Maker validation" do
4
- it "requires a block for :add_entrypoint" do
5
- expect {
6
- Class.new(DSL::Maker) do
7
- add_entrypoint(:pizza)
8
- end
9
- }.to raise_error('Block required for add_entrypoint')
10
- end
11
-
12
4
  it "requires a block for :generate_dsl" do
13
5
  expect {
14
6
  Class.new(DSL::Maker) do
@@ -19,71 +11,103 @@ describe "DSL::Maker validation" do
19
11
  }.to raise_error('Block required for generate_dsl')
20
12
  end
21
13
 
22
- it "requires a recognized type for attributes" do
23
- expect {
24
- Class.new(DSL::Maker) do
25
- add_entrypoint(:pizza, {
26
- :cheese => true,
27
- }) do
28
- Pizza.new(cheese, nil, nil, nil)
29
- end
30
- end
31
- }.to raise_error("Unrecognized element type 'true'")
32
- end
33
-
34
- it "rejects attributes which block Boolean helper methods" do
35
- %w(yes no on off __apply).each do |name|
14
+ describe "for attributes" do
15
+ it "requires a recognized type for attributes" do
36
16
  expect {
37
17
  Class.new(DSL::Maker) do
38
18
  add_entrypoint(:pizza, {
39
- name => String,
19
+ :cheese => true,
40
20
  }) do
41
21
  Pizza.new(cheese, nil, nil, nil)
42
22
  end
43
23
  end
44
- }.to raise_error("Illegal attribute name '#{name}'")
24
+ }.to raise_error("Unrecognized element type 'true'")
45
25
  end
46
- end
47
26
 
48
- it "rejects re-using an entrypoint name in add_entrypoint()" do
49
- dsl_class = Class.new(DSL::Maker) do
50
- add_entrypoint(:x, {}) { nil }
27
+ it "rejects attributes which block Boolean helper methods" do
28
+ %w(yes no on off __apply).each do |name|
29
+ expect {
30
+ Class.new(DSL::Maker) do
31
+ add_entrypoint(:pizza, {
32
+ name => String,
33
+ }) do
34
+ Pizza.new(cheese, nil, nil, nil)
35
+ end
36
+ end
37
+ }.to raise_error("Illegal attribute name '#{name}'")
38
+ end
51
39
  end
52
- expect {
53
- dsl_class.add_entrypoint(:x, {}) { nil }
54
- }.to raise_error("'x' is already an entrypoint")
55
40
  end
56
41
 
57
- it "rejects an entrypoint name that doesn't exist in entrypoint()" do
58
- dsl_class = Class.new(DSL::Maker)
42
+ describe "for entrypoints" do
43
+ it "requires a block for :add_entrypoint" do
44
+ expect {
45
+ Class.new(DSL::Maker) do
46
+ add_entrypoint(:pizza)
47
+ end
48
+ }.to raise_error('Block required for add_entrypoint')
49
+ end
59
50
 
60
- expect {
61
- dsl_class.entrypoint(:x)
62
- }.to raise_error("'x' is not an entrypoint")
63
- end
51
+ it "rejects re-using an entrypoint name in add_entrypoint()" do
52
+ dsl_class = Class.new(DSL::Maker) do
53
+ add_entrypoint(:x, {}) { nil }
54
+ end
55
+ expect {
56
+ dsl_class.add_entrypoint(:x, {}) { nil }
57
+ }.to raise_error("'x' is already an entrypoint")
58
+ end
64
59
 
65
- it "rejects a helper without a block" do
66
- dsl_class = Class.new(DSL::Maker)
60
+ it "rejects an entrypoint name that doesn't exist in entrypoint()" do
61
+ dsl_class = Class.new(DSL::Maker)
67
62
 
68
- expect {
69
- dsl_class.add_helper(:x)
70
- }.to raise_error('Block required for add_helper')
63
+ expect {
64
+ dsl_class.entrypoint(:x)
65
+ }.to raise_error("'x' is not an entrypoint")
66
+ end
71
67
  end
72
68
 
73
- it "rejects the helper name default" do
74
- dsl_class = Class.new(DSL::Maker)
69
+ describe "for helpers" do
70
+ it "rejects a helper without a block" do
71
+ dsl_class = Class.new(DSL::Maker)
75
72
 
76
- expect {
77
- dsl_class.add_helper(:default) {}
78
- }.to raise_error("'default' is already a helper")
79
- end
73
+ expect {
74
+ dsl_class.add_helper(:x)
75
+ }.to raise_error('Block required for add_helper')
76
+ end
80
77
 
81
- it "rejects a helper name already in use" do
82
- dsl_class = Class.new(DSL::Maker)
83
- dsl_class.add_helper(:x) {}
78
+ it "rejects the helper name default" do
79
+ dsl_class = Class.new(DSL::Maker)
84
80
 
85
- expect {
81
+ expect {
82
+ dsl_class.add_helper(:default) {}
83
+ }.to raise_error("'default' is already a helper")
84
+ end
85
+
86
+ it "rejects a helper name already in use" do
87
+ dsl_class = Class.new(DSL::Maker)
86
88
  dsl_class.add_helper(:x) {}
87
- }.to raise_error("'x' is already a helper")
89
+
90
+ expect {
91
+ dsl_class.add_helper(:x) {}
92
+ }.to raise_error("'x' is already a helper")
93
+ end
94
+ end
95
+
96
+ describe "for type coercions" do
97
+ it "rejects a type coercion without a block" do
98
+ dsl_class = Class.new(DSL::Maker)
99
+
100
+ expect {
101
+ dsl_class.add_type(:x)
102
+ }.to raise_error('Block required for add_type')
103
+ end
104
+
105
+ it "rejects a type coercion type already in use" do
106
+ dsl_class = Class.new(DSL::Maker)
107
+
108
+ expect {
109
+ dsl_class.add_type(String) {}
110
+ }.to raise_error("'String' is already a type coercion")
111
+ end
88
112
  end
89
113
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dsl_maker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Kinyon