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 +4 -4
- data/Changes +6 -0
- data/README.md +13 -7
- data/lib/dsl/maker/version.rb +1 -1
- data/lib/dsl/maker.rb +71 -37
- data/spec/class_as_subdsl_spec.rb +4 -4
- data/spec/error_spec.rb +77 -53
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf937996460904dce3266547aab1e117ee498e8d
|
4
|
+
data.tar.gz: 85796fbba9b301299057952af7b5b72bda58d4cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
328
|
+
There are four pre-defined type coercions for use within `generate_dsl()`:
|
322
329
|
|
323
|
-
* String - This takes
|
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
|
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
|
|
data/lib/dsl/maker/version.rb
CHANGED
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
|
-
@@
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
-
|
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 @@
|
139
|
-
@@
|
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 =>
|
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(
|
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 =>
|
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(
|
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
|
-
|
23
|
-
|
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
|
-
|
19
|
+
:cheese => true,
|
40
20
|
}) do
|
41
21
|
Pizza.new(cheese, nil, nil, nil)
|
42
22
|
end
|
43
23
|
end
|
44
|
-
}.to raise_error("
|
24
|
+
}.to raise_error("Unrecognized element type 'true'")
|
45
25
|
end
|
46
|
-
end
|
47
26
|
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
58
|
-
|
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
|
-
|
61
|
-
dsl_class.
|
62
|
-
|
63
|
-
|
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
|
-
|
66
|
-
|
60
|
+
it "rejects an entrypoint name that doesn't exist in entrypoint()" do
|
61
|
+
dsl_class = Class.new(DSL::Maker)
|
67
62
|
|
68
|
-
|
69
|
-
|
70
|
-
|
63
|
+
expect {
|
64
|
+
dsl_class.entrypoint(:x)
|
65
|
+
}.to raise_error("'x' is not an entrypoint")
|
66
|
+
end
|
71
67
|
end
|
72
68
|
|
73
|
-
|
74
|
-
|
69
|
+
describe "for helpers" do
|
70
|
+
it "rejects a helper without a block" do
|
71
|
+
dsl_class = Class.new(DSL::Maker)
|
75
72
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
73
|
+
expect {
|
74
|
+
dsl_class.add_helper(:x)
|
75
|
+
}.to raise_error('Block required for add_helper')
|
76
|
+
end
|
80
77
|
|
81
|
-
|
82
|
-
|
83
|
-
dsl_class.add_helper(:x) {}
|
78
|
+
it "rejects the helper name default" do
|
79
|
+
dsl_class = Class.new(DSL::Maker)
|
84
80
|
|
85
|
-
|
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
|
-
|
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
|