dsl_maker 0.0.8 → 0.0.9

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: fd8b809906f6bde7d8b1839095dc2ad018148190
4
- data.tar.gz: 13708d81d5f96de3f5744736c77f4b55ef2d5748
3
+ metadata.gz: 0338de58f7a2ecf13d08d203c4682bde172292f5
4
+ data.tar.gz: cc00e4a818b4aeb8b84841874878cd0851611703
5
5
  SHA512:
6
- metadata.gz: d0c2f6464bc5d08693a7298dae3074c9f89f00c9f2959bb1366b86a5cfdf211bc6fc779c045cb111fd04f0e0e7aff1aa8304ccd895d084fa32119e4fdba7c951
7
- data.tar.gz: c9ecc30fba1b36b6c6aac878de49a6191df39180ef05dd96996a411e82c5c52e44ef202254ba08736755e95fe9d8df3fba94ad512adc51ddc6d139d96f1a987a
6
+ metadata.gz: 5b272b83ae0a2485dbe1890172fbf03ac7cf4885cfd97d21b853008f7cbd30c930b2f7734f1ec886c5d2924e46fc41bc1853bccec8223997e7f9af9bd45f8e0a
7
+ data.tar.gz: 1cf59abb5d74f12358e234dde90d072348b938e993ab0884487a0715215ab15a5909abc17b11b0954035e81fe32edd11d2ad872dbb17dbd8fdc8aeadcc94b16b
data/Changes CHANGED
@@ -1,5 +1,10 @@
1
1
  Revision history for DSL::Maker (ordered by revision number).
2
2
 
3
+ 0.0.9 Aug 11 2015
4
+ - Added the ArrayOf[<type>] type to allow for arrays to concatenate properly.
5
+ - Added the AliasOf(<name>) type to allow for use of multiple names to refer to
6
+ the same thing.
7
+
3
8
  0.0.8 Aug 07 2015
4
9
  - Make sure to provide a unique value for each type name.
5
10
  - Allow 'Object' to be used as an alias for 'Any'
data/README.md CHANGED
@@ -402,15 +402,28 @@ were encountered.
402
402
 
403
403
  ### Type Coercions
404
404
 
405
- There are four pre-defined type coercions for use within `generate_dsl()`:
405
+ There are four pre-defined standard type coercions available for `generate_dsl()`:
406
406
 
407
- * Any - This takes whatever you give it and returns it back.
408
- * String - This takes whatever you give it and returns the string within it.
409
- * Integer - This takes whatever you give it and returns the integer within it.
410
- * Boolean - This takes whatever you give it and returns the truthiness of it.
411
- * `generate_dsl()` - This descends into another level of DSL.
407
+ Standard coercions:
408
+ * Any - This takes whatever you give it and returns it back.
409
+ * String - This takes whatever you give it and returns the string within it.
410
+ * Integer - This takes whatever you give it and returns the integer within it.
411
+ * Boolean - This takes whatever you give it and returns the truthiness of it.
412
412
 
413
- You can add additional type coercions using `add_type()` as described above.
413
+ You can add additional standard type coercions using `add_type()` as described
414
+ above.
415
+
416
+ There are also three special type coercions that are not creatable with
417
+ `add_type()` because they do special manipulations within DSL::Maker.
418
+
419
+ Special coercions:
420
+ * `generate_dsl()` - This descends into another level of DSL.
421
+ * ArrayOf[<type>] - This creates an array coerced as the <type>. Successive
422
+ invocations are concatenated. <type> can be a DSL.
423
+ * AliasOf(<name>) - this creates an additional name that is synonomous with
424
+ the <name> item. You can use either this name or <name>.
425
+
426
+ These are special-cased within `build_dsl_element()`.
414
427
 
415
428
  ### Helpers
416
429
 
data/lib/dsl/maker.rb CHANGED
@@ -65,6 +65,38 @@ class DSL::Maker
65
65
  Yes = On = True = true
66
66
  No = Off = False = false
67
67
 
68
+ class Alias
69
+ attr_reader :real_name
70
+ def initialize(real_name)
71
+ @real_name = real_name
72
+ end
73
+ end
74
+ @@aliases = {}
75
+ def self.AliasOf(name)
76
+ @@aliases[name] ||= Alias.new(name)
77
+ end
78
+ def self.is_alias(type)
79
+ type.instance_of? Alias
80
+ end
81
+
82
+ class ArrayType
83
+ attr_reader :base_type
84
+ def initialize(base_type)
85
+ @base_type = base_type
86
+ end
87
+ end
88
+ @@arrays = {}
89
+ ArrayOf = Class.new do
90
+ def self.[](type)
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)
93
+ @@arrays[type] ||= ArrayType.new(type)
94
+ end
95
+ end
96
+ def self.is_array(type)
97
+ type.instance_of? ArrayType
98
+ end
99
+
68
100
  # Parse the DSL provided in the parameter.
69
101
  #
70
102
  # @note If the DSL contains multiple entrypoints, then this will return an
@@ -114,13 +146,7 @@ class DSL::Maker
114
146
  raise "Block required for add_type" unless block_given?
115
147
  raise "'#{type}' is already a type coercion" if @@types.has_key? type
116
148
 
117
- @@types[type] = ->(klass, name, type) {
118
- klass.class_eval do
119
- define_method(name.to_sym) do |*args|
120
- instance_exec('@' + name.to_s, *args, &block)
121
- end
122
- end
123
- }
149
+ @@types[type] = block
124
150
 
125
151
  return
126
152
  end
@@ -290,6 +316,8 @@ class DSL::Maker
290
316
  # * Integer - the integer value of whatever you give is returned.
291
317
  # * Boolean - the truthiness of whatever you give is returned.
292
318
  # * generate_dsl() - this represents a new level of the DSL.
319
+ # * AliasOf(<name>) - this aliases a name to another name.
320
+ # * ArrayOf[<type>] - this creates an array of the <type> coercion.
293
321
  #
294
322
  # @param klass [Class] The class representing this level in the DSL.
295
323
  # @param name [String] The name of the element we're working on.
@@ -299,7 +327,11 @@ class DSL::Maker
299
327
  # @return nil
300
328
  def self.build_dsl_element(klass, name, type)
301
329
  if @@types.has_key?(type)
302
- @@types[type].call(klass, name, type)
330
+ klass.class_eval do
331
+ define_method(name.to_sym) do |*args|
332
+ instance_exec('@' + name.to_s, *args, &@@types[type])
333
+ end
334
+ end
303
335
  elsif is_dsl(type)
304
336
  as_attr = '@' + name.to_s
305
337
  klass.class_eval do
@@ -329,6 +361,46 @@ class DSL::Maker
329
361
  ___get(as_attr)
330
362
  end
331
363
  end
364
+ elsif is_alias(type)
365
+ klass.class_eval do
366
+ alias_method name, type.real_name
367
+ end
368
+ elsif is_array(type)
369
+ as_attr = '@' + name.to_s
370
+
371
+ klass.class_eval do
372
+ define_method(name.to_sym) do |*args, &dsl_block|
373
+ rv = ___get(as_attr)
374
+ ___set(as_attr, rv = []) unless rv
375
+
376
+ if dsl_block
377
+ # This code is copy-pasted from the is_dsl() section above. Figure out
378
+ # how to hoist this code into something reusable. But, we don't need
379
+ # the parent_class section (do we?)
380
+ obj = type.base_type.new
381
+ Docile.dsl_eval(obj, &dsl_block)
382
+ dsl_value = obj.__apply(*args)
383
+
384
+ if v = type.base_type.instance_variable_get(:@verifications)
385
+ v.each do |verify|
386
+ failure = verify.call(dsl_value)
387
+ raise failure if failure
388
+ end
389
+ end
390
+
391
+ rv.push(dsl_value)
392
+ elsif !args.empty?
393
+ rv.concat(
394
+ args.map do |item|
395
+ # Assumption: 10x_ will never be used as an attribute name.
396
+ klass.new.instance_exec('@__________', item, &@@types[type.base_type])
397
+ end
398
+ )
399
+ end
400
+
401
+ rv
402
+ end
403
+ end
332
404
  else
333
405
  raise "Unrecognized element type '#{type}'"
334
406
  end
@@ -356,7 +428,6 @@ class DSL::Maker
356
428
 
357
429
  def self.is_entrypoint(name)
358
430
  @entrypoints && @entrypoints.has_key?(name.to_sym)
359
- #@klass && @klass.new.respond_to?(name.to_sym)
360
431
  end
361
432
  end
362
433
 
@@ -1,6 +1,6 @@
1
1
  module DSL
2
2
  class Maker
3
3
  # The current version of this library
4
- VERSION = '0.0.8'
4
+ VERSION = '0.0.9'
5
5
  end
6
6
  end
@@ -0,0 +1,91 @@
1
+ # This is to test the AliasOf(:name) type
2
+
3
+ describe "Packager DSL AliasOf" do
4
+ # This uses $toppings defined in spec/spec_helper.rb
5
+ def verify_pizza(pizza, values={})
6
+ expect(pizza).to be_instance_of(Structs::Pizza)
7
+ $toppings.each do |topping|
8
+ expect(pizza.send(topping)).to eq(values[topping])
9
+ end
10
+ end
11
+
12
+ it "can alias a Boolean" do
13
+ dsl_class = Class.new(DSL::Maker) do
14
+ add_entrypoint(:pizza, {
15
+ :cheese => DSL::Maker::Boolean,
16
+ :cheeseyness => DSL::Maker::AliasOf(:cheese),
17
+ }) {
18
+ Structs::Pizza.new(cheeseyness)
19
+ }
20
+ end
21
+
22
+ pizza = dsl_class.execute_dsl {
23
+ pizza { cheese yes }
24
+ }
25
+ verify_pizza(pizza, :cheese => true)
26
+ end
27
+
28
+ it "can alias multiple times" do
29
+ dsl_class = Class.new(DSL::Maker) do
30
+ add_entrypoint(:pizza, {
31
+ :cheese => DSL::Maker::Boolean,
32
+ :cheeseyness => DSL::Maker::AliasOf(:cheese),
33
+ :fromage => DSL::Maker::AliasOf(:cheese),
34
+ }) {
35
+ Structs::Pizza.new(cheeseyness)
36
+ }
37
+ end
38
+
39
+ pizza = dsl_class.execute_dsl {
40
+ pizza { fromage yes }
41
+ }
42
+ verify_pizza(pizza, :cheese => true)
43
+ end
44
+
45
+ it "can have many different aliases" do
46
+ dsl_class = Class.new(DSL::Maker) do
47
+ add_entrypoint(:pizza, {
48
+ :cheese => DSL::Maker::Boolean,
49
+ :fromage => DSL::Maker::AliasOf(:cheese),
50
+ :bacon => DSL::Maker::Boolean,
51
+ :panceta => DSL::Maker::AliasOf(:bacon),
52
+ }) {
53
+ Structs::Pizza.new(fromage, nil, panceta)
54
+ }
55
+ end
56
+
57
+ pizza = dsl_class.execute_dsl {
58
+ pizza {
59
+ cheese yes
60
+ bacon yes
61
+ }
62
+ }
63
+ verify_pizza(pizza, :cheese => true, :bacon => true)
64
+ end
65
+
66
+ it "can alias a DSL" do
67
+ dsl_class = Class.new(DSL::Maker) do
68
+ add_entrypoint(:pizza, {
69
+ :cheese => generate_dsl({
70
+ :type => String,
71
+ :color => String,
72
+ }) do
73
+ Structs::Cheese.new(type, color)
74
+ end,
75
+ :cheeseyness => DSL::Maker::AliasOf(:cheese)
76
+ }) {
77
+ Structs::Pizza.new(cheeseyness)
78
+ }
79
+ end
80
+
81
+ pizza = dsl_class.execute_dsl {
82
+ pizza {
83
+ cheese {
84
+ type 'mozzarrella'
85
+ color 'white'
86
+ }
87
+ }
88
+ }
89
+ verify_pizza(pizza, :cheese => Structs::Cheese.new('mozzarrella', 'white'))
90
+ end
91
+ end
@@ -0,0 +1,135 @@
1
+ describe "Packager DSL ArrayOf" do
2
+ # This uses $toppings defined in spec/spec_helper.rb
3
+ def verify_pizza(pizza, values={})
4
+ expect(pizza).to be_instance_of(Structs::Pizza)
5
+ $toppings.each do |topping|
6
+ expect(pizza.send(topping)).to eq(values[topping])
7
+ end
8
+ end
9
+
10
+ it "can array a String" do
11
+ dsl_class = Class.new(DSL::Maker) do
12
+ add_entrypoint(:pizza, {
13
+ :cheeses => DSL::Maker::ArrayOf[String],
14
+ :cheese => DSL::Maker::AliasOf(:cheeses),
15
+ }) {
16
+ Structs::Pizza.new(cheeses)
17
+ }
18
+ end
19
+
20
+ pizza = dsl_class.execute_dsl {
21
+ pizza {
22
+ cheeses :cheddar
23
+ cheeses 'mozzarrella'
24
+ }
25
+ }
26
+ verify_pizza(pizza, :cheese => %w(cheddar mozzarrella))
27
+
28
+ pizza = dsl_class.execute_dsl {
29
+ pizza {
30
+ cheeses 'cheddar', 'mozzarrella'
31
+ }
32
+ }
33
+ verify_pizza(pizza, :cheese => %w(cheddar mozzarrella))
34
+ end
35
+
36
+ it "can array a DSL" do
37
+ dsl_class = Class.new(DSL::Maker) do
38
+ cheese_dsl = generate_dsl({
39
+ :type => String,
40
+ :color => String,
41
+ }) do
42
+ Structs::Cheese.new(type, color)
43
+ end
44
+
45
+ add_entrypoint(:pizza, {
46
+ :cheeses => DSL::Maker::ArrayOf[cheese_dsl],
47
+ :cheese => DSL::Maker::AliasOf(:cheeses),
48
+ }) {
49
+ Structs::Pizza.new(cheeses)
50
+ }
51
+ end
52
+
53
+ pizza = dsl_class.execute_dsl {
54
+ pizza {
55
+ cheese {
56
+ type 'mozzarrella'
57
+ color 'white'
58
+ }
59
+ cheese {
60
+ type 'cheddar'
61
+ color 'orange'
62
+ }
63
+ }
64
+ }
65
+ verify_pizza(pizza, :cheese => [
66
+ Structs::Cheese.new('mozzarrella', 'white'),
67
+ Structs::Cheese.new('cheddar', 'orange'),
68
+ ])
69
+ end
70
+
71
+ it "can array a DSL with verifications" do
72
+ dsl_class = Class.new(DSL::Maker) do
73
+ cheese_dsl = generate_dsl({
74
+ :type => String,
75
+ :color => String,
76
+ }) do
77
+ Structs::Cheese.new(type, color)
78
+ end
79
+ cheese_dsl.add_verification do |item|
80
+ return "Cheese must have a color" unless item.color
81
+ end
82
+
83
+ add_entrypoint(:pizza, {
84
+ :cheeses => DSL::Maker::ArrayOf[cheese_dsl],
85
+ :cheese => DSL::Maker::AliasOf(:cheeses),
86
+ }) {
87
+ Structs::Pizza.new(cheeses)
88
+ }
89
+ end
90
+
91
+ expect {
92
+ dsl_class.execute_dsl {
93
+ pizza {
94
+ cheese {
95
+ type 'mozzarrella'
96
+ }
97
+ }
98
+ }
99
+ }.to raise_error("Cheese must have a color")
100
+ end
101
+
102
+ it "can array a DSL with arguments" do
103
+ dsl_class = Class.new(DSL::Maker) do
104
+ cheese_dsl = generate_dsl({
105
+ :type => String,
106
+ :color => String,
107
+ }) do |*args|
108
+ default(:type, args, 0)
109
+ Structs::Cheese.new(type, color)
110
+ end
111
+
112
+ add_entrypoint(:pizza, {
113
+ :cheeses => DSL::Maker::ArrayOf[cheese_dsl],
114
+ :cheese => DSL::Maker::AliasOf(:cheeses),
115
+ }) {
116
+ Structs::Pizza.new(cheeses)
117
+ }
118
+ end
119
+
120
+ pizza = dsl_class.execute_dsl {
121
+ pizza {
122
+ cheese 'mozzarrella' do
123
+ color 'white'
124
+ end
125
+ cheese 'cheddar' do
126
+ color 'orange'
127
+ end
128
+ }
129
+ }
130
+ verify_pizza(pizza, :cheese => [
131
+ Structs::Cheese.new('mozzarrella', 'white'),
132
+ Structs::Cheese.new('cheddar', 'orange'),
133
+ ])
134
+ end
135
+ end
data/spec/error_spec.rb CHANGED
@@ -167,5 +167,25 @@ describe "DSL::Maker validation" do
167
167
  dsl_class.add_type(String) {}
168
168
  }.to raise_error("'String' is already a type coercion")
169
169
  end
170
+
171
+ it "rejects an ArrayOf[type] if type isn't known" do
172
+ expect {
173
+ Class.new(DSL::Maker) do
174
+ generate_dsl({
175
+ :foo => DSL::Maker::ArrayOf[:does_not_exist]
176
+ }) {}
177
+ end
178
+ }.to raise_error("Unknown type provided to ArrayOf")
179
+ end
180
+
181
+ it "rejects an ArrayOf[type] if type is an alias" do
182
+ expect {
183
+ Class.new(DSL::Maker) do
184
+ generate_dsl({
185
+ :foo => DSL::Maker::ArrayOf[DSL::Maker::AliasOf(:foo)]
186
+ }) {}
187
+ end
188
+ }.to raise_error("Cannot make an array of an alias")
189
+ end
170
190
  end
171
191
  end
data/spec/spec_helper.rb CHANGED
@@ -40,6 +40,7 @@ module Structs
40
40
 
41
41
  $toppings = [:cheese, :pepperoni, :bacon, :sauce]
42
42
  Pizza = Struct.new(*$toppings)
43
+ Cheese = Struct.new(:type, :color)
43
44
 
44
45
  Color = Struct.new(:name)
45
46
  Fruit = Struct.new(:name, :color)
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.0.8
4
+ version: 0.0.9
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-07 00:00:00.000000000 Z
11
+ date: 2015-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docile
@@ -154,7 +154,9 @@ files:
154
154
  - lib/dsl/maker.rb
155
155
  - lib/dsl/maker/version.rb
156
156
  - on_what.rb
157
+ - spec/alias_type_spec.rb
157
158
  - spec/args_spec.rb
159
+ - spec/array_type_spec.rb
158
160
  - spec/class_as_subdsl_spec.rb
159
161
  - spec/error_spec.rb
160
162
  - spec/helper_spec.rb