dsl_maker 0.0.2 → 0.0.3
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 +7 -1
- data/Rakefile +1 -1
- data/lib/dsl/maker/version.rb +1 -1
- data/lib/dsl/maker.rb +67 -40
- data/spec/args_spec.rb +20 -20
- data/spec/class_as_subdsl_spec.rb +83 -0
- data/spec/error_spec.rb +17 -0
- data/spec/multi_level_spec.rb +16 -16
- data/spec/multiple_invocation_spec.rb +16 -16
- data/spec/single_level_spec.rb +7 -7
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dcf7e27a270d732f50700ad02cc0e2df6410d31
|
4
|
+
data.tar.gz: 67af6f9d5095417301601997d3f4244d6887a329
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3c69f7f5890b5266ec5a00a6e2c7d3238f50839ee5f527887024d63b90d146c4959b11f69575753d77ba1f6f3add5f8bbb6957533d8960428c0cdcd0c7c92c5
|
7
|
+
data.tar.gz: 3a78ff0dfce77a4c3e358400864110c068f102698a7aace6741315369f0956f80b55fb92431302ad8d262eb877fe48c955d08960c70dce0a6dac50c2b5d6a8c5
|
data/Changes
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
Revision history for DSL::Maker (ordered by revision number).
|
2
2
|
|
3
|
+
0.0.3 Jul 28 2015
|
4
|
+
- Added entrypoint() that returns the DSL implementing an entrypoint
|
5
|
+
- Several refactorings to improve maintainability:
|
6
|
+
- DSL::Maker::Boolean is now a mixin, not a base class
|
7
|
+
- DSL::Maker::Base is now the base class for all the DSL classes
|
8
|
+
|
3
9
|
0.0.2 Jul 22 2015
|
4
10
|
- Allow add_entrypoint() to take a DSL class instead of args
|
5
11
|
- Added execute_dsl() that takes a block
|
6
|
-
- Several refactorings to improve maintainability
|
12
|
+
- Several refactorings to improve maintainability:
|
7
13
|
- Recursive DSLs are now simpler to define and maintain
|
8
14
|
|
9
15
|
0.0.1 Jul 21 2015
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ task :default => [:spec]
|
|
12
12
|
RSpec::Core::RakeTask.new
|
13
13
|
|
14
14
|
# Configure `rake clobber` to delete all generated files
|
15
|
-
CLOBBER.include('pkg', 'doc', 'coverage')
|
15
|
+
CLOBBER.include('pkg', 'doc', 'coverage', '*.gem')
|
16
16
|
|
17
17
|
if !on_travis? && !on_jruby? && !on_1_8?
|
18
18
|
require 'github/markup'
|
data/lib/dsl/maker/version.rb
CHANGED
data/lib/dsl/maker.rb
CHANGED
@@ -4,15 +4,8 @@ require 'docile'
|
|
4
4
|
|
5
5
|
# This is the base class we provide.
|
6
6
|
class DSL::Maker
|
7
|
-
# This is
|
8
|
-
class
|
9
|
-
{
|
10
|
-
:yes => true, :no => false,
|
11
|
-
:on => true, :off => false,
|
12
|
-
}.each do |name, result|
|
13
|
-
define_method(name) { result }
|
14
|
-
end
|
15
|
-
|
7
|
+
# This is the base class for all DSL-parsing classes.
|
8
|
+
class Base
|
16
9
|
# 21 character method names are obscene. Make it easier to read.
|
17
10
|
alias :___set :instance_variable_set
|
18
11
|
|
@@ -34,18 +27,26 @@ class DSL::Maker
|
|
34
27
|
return
|
35
28
|
end
|
36
29
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
|
31
|
+
# This is a useful module that contains all the Boolean handling we need.
|
32
|
+
module Boolean
|
33
|
+
{
|
34
|
+
:yes => true, :no => false,
|
35
|
+
:on => true, :off => false,
|
36
|
+
}.each do |name, result|
|
37
|
+
define_method(name) { result }
|
42
38
|
end
|
43
|
-
# The bang-bang boolean-izes the value. We want this to be lossy.
|
44
|
-
!!value
|
45
|
-
end
|
46
39
|
|
47
|
-
|
48
|
-
|
40
|
+
def self.coerce(value)
|
41
|
+
if value
|
42
|
+
return false if %w(no off false nil).include? value.to_s.downcase
|
43
|
+
end
|
44
|
+
# The bang-bang boolean-izes the value. We want this to be lossy.
|
45
|
+
!!value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
Yes = On = True = true
|
49
|
+
No = Off = False = false
|
49
50
|
|
50
51
|
# Parse the DSL provided in the parameter.
|
51
52
|
#
|
@@ -56,14 +57,14 @@ class DSL::Maker
|
|
56
57
|
#
|
57
58
|
# @return [Object] Whatever is returned by the block defined in this class.
|
58
59
|
def self.parse_dsl(dsl)
|
59
|
-
# add_entrypoint() will use
|
60
|
+
# add_entrypoint() will use @accumulator to handle multiple entrypoints.
|
60
61
|
# Reset it here so that we're only handling the values from this run.
|
61
|
-
|
62
|
+
@accumulator = []
|
62
63
|
eval dsl, self.get_binding
|
63
|
-
if
|
64
|
-
return
|
64
|
+
if @accumulator.length <= 1
|
65
|
+
return @accumulator[0]
|
65
66
|
end
|
66
|
-
return
|
67
|
+
return @accumulator
|
67
68
|
end
|
68
69
|
|
69
70
|
# Execute the DSL provided in the block.
|
@@ -75,14 +76,23 @@ class DSL::Maker
|
|
75
76
|
#
|
76
77
|
# @return [Object] Whatever is returned by &block
|
77
78
|
def self.execute_dsl(&block)
|
78
|
-
|
79
|
+
@accumulator = []
|
79
80
|
instance_eval(&block)
|
80
|
-
if
|
81
|
-
return
|
81
|
+
if @accumulator.length <= 1
|
82
|
+
return @accumulator[0]
|
82
83
|
end
|
83
|
-
return
|
84
|
+
return @accumulator
|
84
85
|
end
|
85
86
|
|
87
|
+
# Returns the binding as needed by parse_dsl() and execute_dsl()
|
88
|
+
#
|
89
|
+
# @return [Binding] The binding of the invoking class.
|
90
|
+
def self.get_binding
|
91
|
+
binding
|
92
|
+
end
|
93
|
+
|
94
|
+
# FIXME: This may have to be changed when the elements can be altered because
|
95
|
+
# it is global to the hierarchy. But, that may be desirable.
|
86
96
|
@@dsl_elements = {
|
87
97
|
String => ->(klass, name, type) {
|
88
98
|
as_attr = '@' + name.to_s
|
@@ -93,11 +103,11 @@ class DSL::Maker
|
|
93
103
|
end
|
94
104
|
end
|
95
105
|
},
|
96
|
-
Boolean => ->(klass, name, type) {
|
106
|
+
DSL::Maker::Boolean => ->(klass, name, type) {
|
97
107
|
as_attr = '@' + name.to_s
|
98
108
|
klass.class_eval do
|
99
109
|
define_method(name.to_sym) do |*args|
|
100
|
-
___set(as_attr,
|
110
|
+
___set(as_attr, Boolean.coerce(args[0])) unless args.empty?
|
101
111
|
# Ensure that the default nil returns as false.
|
102
112
|
!!___get(as_attr)
|
103
113
|
end
|
@@ -105,6 +115,10 @@ class DSL::Maker
|
|
105
115
|
},
|
106
116
|
}
|
107
117
|
|
118
|
+
$is_dsl = lambda do |proto|
|
119
|
+
proto.is_a?(Class) && proto.ancestors.include?(DSL::Maker::Base)
|
120
|
+
end
|
121
|
+
|
108
122
|
# Add a single element of a DSL to a class representing a level in a DSL.
|
109
123
|
#
|
110
124
|
# Each of the types represents a coercion - a guarantee and check of the value
|
@@ -123,7 +137,7 @@ class DSL::Maker
|
|
123
137
|
def self.build_dsl_element(klass, name, type)
|
124
138
|
if @@dsl_elements.has_key?(type)
|
125
139
|
@@dsl_elements[type].call(klass, name, type)
|
126
|
-
elsif
|
140
|
+
elsif $is_dsl.call(type)
|
127
141
|
as_attr = '@' + name.to_s
|
128
142
|
klass.class_eval do
|
129
143
|
define_method(name.to_sym) do |*args, &dsl_block|
|
@@ -163,7 +177,9 @@ class DSL::Maker
|
|
163
177
|
# Inherit from the Boolean class to gain access to the useful methods
|
164
178
|
# TODO: Convert DSL::Maker::Boolean into a Role
|
165
179
|
# TODO: Create a DSL::Maker::Base class to inherit from
|
166
|
-
dsl_class = Class.new(
|
180
|
+
dsl_class = Class.new(DSL::Maker::Base) do
|
181
|
+
include DSL::Maker::Boolean
|
182
|
+
|
167
183
|
# This instance method exists because we cannot seem to inline its work
|
168
184
|
# where we call it. Could it be a problem of incorrect binding?
|
169
185
|
# It has to be defined here because it needs access to &defn_block
|
@@ -201,16 +217,13 @@ class DSL::Maker
|
|
201
217
|
# TODO: Provide a default block that returns the datastructure as a HoH.
|
202
218
|
raise "Block required for add_entrypoint" unless block_given?
|
203
219
|
|
204
|
-
|
205
|
-
|
206
|
-
# because this is the only place we know for certain will be called.
|
207
|
-
unless self.respond_to? :get_binding
|
208
|
-
define_singleton_method(:get_binding) { binding }
|
220
|
+
if self.respond_to?(name.to_sym)
|
221
|
+
raise "'#{name.to_s}' is already an entrypoint"
|
209
222
|
end
|
210
223
|
|
211
224
|
# FIXME: This is a wart. Really, we should be pulling out name, then
|
212
225
|
# yielding to generate_dsl() in some fashion.
|
213
|
-
if
|
226
|
+
if $is_dsl.call(args)
|
214
227
|
dsl_class = args
|
215
228
|
else
|
216
229
|
dsl_class = generate_dsl(args, &defn_block)
|
@@ -220,10 +233,24 @@ class DSL::Maker
|
|
220
233
|
obj = dsl_class.new
|
221
234
|
Docile.dsl_eval(obj, &dsl_block) if dsl_block
|
222
235
|
rv = obj.instance_exec(*args, &defn_block)
|
223
|
-
|
236
|
+
@accumulator.push(rv)
|
224
237
|
return rv
|
225
238
|
end
|
226
239
|
|
227
|
-
|
240
|
+
@entrypoints ||= {}
|
241
|
+
return @entrypoints[name.to_sym] = dsl_class
|
242
|
+
end
|
243
|
+
|
244
|
+
# This returns the DSL corresponding to the entrypoint's name.
|
245
|
+
#
|
246
|
+
# @param name [String] the name of the entrypoint
|
247
|
+
#
|
248
|
+
# @return [Class] The class that implements this name's DSL definition.
|
249
|
+
def self.entrypoint(name)
|
250
|
+
unless self.respond_to?(name.to_sym)
|
251
|
+
raise "'#{name.to_s}' is not an entrypoint"
|
252
|
+
end
|
253
|
+
|
254
|
+
return @entrypoints[name.to_sym]
|
228
255
|
end
|
229
256
|
end
|
data/spec/args_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# This will use a DSL that defines fruit
|
2
2
|
|
3
3
|
describe "A DSL with argument handling describing fruit" do
|
4
|
-
Color = Struct.new(:name)
|
5
|
-
Fruit = Struct.new(:name, :color)
|
4
|
+
$Color = Struct.new(:name)
|
5
|
+
$Fruit = Struct.new(:name, :color)
|
6
6
|
|
7
7
|
describe "with one argument in add_entrypoint" do
|
8
8
|
dsl_class = Class.new(DSL::Maker) do
|
@@ -10,7 +10,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
10
10
|
:name => String,
|
11
11
|
}) do |*args|
|
12
12
|
default(:name, args, 0)
|
13
|
-
Fruit.new(name, nil)
|
13
|
+
$Fruit.new(name, nil)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -18,7 +18,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
18
18
|
fruit = dsl_class.parse_dsl("
|
19
19
|
fruit
|
20
20
|
")
|
21
|
-
expect(fruit).to be_instance_of(Fruit)
|
21
|
+
expect(fruit).to be_instance_of($Fruit)
|
22
22
|
expect(fruit.name).to be_nil
|
23
23
|
end
|
24
24
|
|
@@ -26,7 +26,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
26
26
|
fruit = dsl_class.parse_dsl("
|
27
27
|
fruit { name 'banana' }
|
28
28
|
")
|
29
|
-
expect(fruit).to be_instance_of(Fruit)
|
29
|
+
expect(fruit).to be_instance_of($Fruit)
|
30
30
|
expect(fruit.name).to eq('banana')
|
31
31
|
end
|
32
32
|
|
@@ -34,7 +34,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
34
34
|
fruit = dsl_class.parse_dsl("
|
35
35
|
fruit 'banana'
|
36
36
|
")
|
37
|
-
expect(fruit).to be_instance_of(Fruit)
|
37
|
+
expect(fruit).to be_instance_of($Fruit)
|
38
38
|
expect(fruit.name).to eq('banana')
|
39
39
|
end
|
40
40
|
|
@@ -45,7 +45,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
45
45
|
name 'banana'
|
46
46
|
end
|
47
47
|
")
|
48
|
-
expect(fruit).to be_instance_of(Fruit)
|
48
|
+
expect(fruit).to be_instance_of($Fruit)
|
49
49
|
expect(fruit.name).to eq('banana')
|
50
50
|
end
|
51
51
|
end
|
@@ -59,7 +59,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
59
59
|
default('name', args)
|
60
60
|
default('color', args, 1)
|
61
61
|
|
62
|
-
Fruit.new(name, color)
|
62
|
+
$Fruit.new(name, color)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -67,7 +67,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
67
67
|
fruit = dsl_class.parse_dsl("
|
68
68
|
fruit
|
69
69
|
")
|
70
|
-
expect(fruit).to be_instance_of(Fruit)
|
70
|
+
expect(fruit).to be_instance_of($Fruit)
|
71
71
|
expect(fruit.name).to be_nil
|
72
72
|
expect(fruit.color).to be_nil
|
73
73
|
end
|
@@ -79,7 +79,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
79
79
|
color 'yellow'
|
80
80
|
}
|
81
81
|
")
|
82
|
-
expect(fruit).to be_instance_of(Fruit)
|
82
|
+
expect(fruit).to be_instance_of($Fruit)
|
83
83
|
expect(fruit.name).to eq('banana')
|
84
84
|
expect(fruit.color).to eq('yellow')
|
85
85
|
|
@@ -89,7 +89,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
89
89
|
color 'green'
|
90
90
|
end
|
91
91
|
")
|
92
|
-
expect(fruit).to be_instance_of(Fruit)
|
92
|
+
expect(fruit).to be_instance_of($Fruit)
|
93
93
|
expect(fruit.name).to eq('plantain')
|
94
94
|
expect(fruit.color).to eq('green')
|
95
95
|
end
|
@@ -98,7 +98,7 @@ describe "A DSL with argument handling describing fruit" do
|
|
98
98
|
fruit = dsl_class.parse_dsl("
|
99
99
|
fruit 'banana', 'yellow'
|
100
100
|
")
|
101
|
-
expect(fruit).to be_instance_of(Fruit)
|
101
|
+
expect(fruit).to be_instance_of($Fruit)
|
102
102
|
expect(fruit.name).to eq('banana')
|
103
103
|
expect(fruit.color).to eq('yellow')
|
104
104
|
end
|
@@ -112,11 +112,11 @@ describe "A DSL with argument handling describing fruit" do
|
|
112
112
|
:name => String,
|
113
113
|
}) { |*args|
|
114
114
|
default('name', args, 0)
|
115
|
-
Color.new(name)
|
115
|
+
$Color.new(name)
|
116
116
|
}
|
117
117
|
}) do |*args|
|
118
118
|
default('name', args, 0)
|
119
|
-
Fruit.new(name, color)
|
119
|
+
$Fruit.new(name, color)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
@@ -128,9 +128,9 @@ describe "A DSL with argument handling describing fruit" do
|
|
128
128
|
}
|
129
129
|
end
|
130
130
|
")
|
131
|
-
expect(fruit).to be_instance_of(Fruit)
|
131
|
+
expect(fruit).to be_instance_of($Fruit)
|
132
132
|
expect(fruit.name).to eq('banana')
|
133
|
-
expect(fruit.color).to be_instance_of(Color)
|
133
|
+
expect(fruit.color).to be_instance_of($Color)
|
134
134
|
expect(fruit.color.name).to eq('yellow')
|
135
135
|
end
|
136
136
|
|
@@ -140,9 +140,9 @@ describe "A DSL with argument handling describing fruit" do
|
|
140
140
|
color 'yellow'
|
141
141
|
end
|
142
142
|
")
|
143
|
-
expect(fruit).to be_instance_of(Fruit)
|
143
|
+
expect(fruit).to be_instance_of($Fruit)
|
144
144
|
expect(fruit.name).to eq('banana')
|
145
|
-
expect(fruit.color).to be_instance_of(Color)
|
145
|
+
expect(fruit.color).to be_instance_of($Color)
|
146
146
|
expect(fruit.color.name).to eq('yellow')
|
147
147
|
end
|
148
148
|
|
@@ -154,9 +154,9 @@ describe "A DSL with argument handling describing fruit" do
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
")
|
157
|
-
expect(fruit).to be_instance_of(Fruit)
|
157
|
+
expect(fruit).to be_instance_of($Fruit)
|
158
158
|
expect(fruit.name).to eq('banana')
|
159
|
-
expect(fruit.color).to be_instance_of(Color)
|
159
|
+
expect(fruit.color).to be_instance_of($Color)
|
160
160
|
expect(fruit.color.name).to eq('green')
|
161
161
|
end
|
162
162
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# This is testing the ability to pass a class into generate_dsl and it
|
2
|
+
# does the right thing.
|
3
|
+
|
4
|
+
describe "Passing a class into generate_dsl" do
|
5
|
+
$Car = Struct.new(:maker, :wheel)
|
6
|
+
$Wheel = Struct.new(:maker, :size)
|
7
|
+
|
8
|
+
it "can do it" do
|
9
|
+
wheel_dsl = Class.new(DSL::Maker) do
|
10
|
+
add_entrypoint(:wheel, {
|
11
|
+
:size => String,
|
12
|
+
:maker => String,
|
13
|
+
}) do |*args|
|
14
|
+
default(:maker, args, 0)
|
15
|
+
$Wheel.new(maker, size)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
dsl_class = Class.new(DSL::Maker) do
|
20
|
+
add_entrypoint(:car, {
|
21
|
+
:maker => String,
|
22
|
+
:wheel => wheel_dsl.entrypoint(:wheel),
|
23
|
+
}) do |*args|
|
24
|
+
default(:maker, args, 0)
|
25
|
+
$Car.new(maker, wheel)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
car = dsl_class.execute_dsl do
|
30
|
+
car 'honda' do
|
31
|
+
wheel 'goodyear' do
|
32
|
+
size 26
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
expect(car).to be_instance_of($Car)
|
37
|
+
expect(car.maker).to eq('honda')
|
38
|
+
expect(car.wheel).to be_instance_of($Wheel)
|
39
|
+
expect(car.wheel.maker).to eq('goodyear')
|
40
|
+
expect(car.wheel.size).to eq('26')
|
41
|
+
end
|
42
|
+
|
43
|
+
# This ensures that if we create multiple entrypoints with the same name, they
|
44
|
+
# won't tramp on each other.
|
45
|
+
it "will not tramp on the entrypoints with the same name" do
|
46
|
+
wheel_dsl = Class.new(DSL::Maker) do
|
47
|
+
add_entrypoint(:wheel, {
|
48
|
+
:size => String,
|
49
|
+
:maker => String,
|
50
|
+
}) do |*args|
|
51
|
+
default(:maker, args, 0)
|
52
|
+
$Wheel.new(maker, size)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
other_wheel_dsl = Class.new(DSL::Maker) do
|
57
|
+
add_entrypoint(:wheel, {}) { nil }
|
58
|
+
end
|
59
|
+
|
60
|
+
dsl_class = Class.new(DSL::Maker) do
|
61
|
+
add_entrypoint(:car, {
|
62
|
+
:maker => String,
|
63
|
+
:wheel => wheel_dsl.entrypoint(:wheel),
|
64
|
+
}) do |*args|
|
65
|
+
default(:maker, args, 0)
|
66
|
+
$Car.new(maker, wheel)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
car = dsl_class.execute_dsl do
|
71
|
+
car 'honda' do
|
72
|
+
wheel 'goodyear' do
|
73
|
+
size 26
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
expect(car).to be_instance_of($Car)
|
78
|
+
expect(car.maker).to eq('honda')
|
79
|
+
expect(car.wheel).to be_instance_of($Wheel)
|
80
|
+
expect(car.wheel.maker).to eq('goodyear')
|
81
|
+
expect(car.wheel.size).to eq('26')
|
82
|
+
end
|
83
|
+
end
|
data/spec/error_spec.rb
CHANGED
@@ -44,4 +44,21 @@ describe "DSL::Maker validation" do
|
|
44
44
|
}.to raise_error("Illegal attribute name '#{name}'")
|
45
45
|
end
|
46
46
|
end
|
47
|
+
|
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 }
|
51
|
+
end
|
52
|
+
expect {
|
53
|
+
dsl_class.add_entrypoint(:x, {}) { nil }
|
54
|
+
}.to raise_error("'x' is already an entrypoint")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "rejects an entrypoint name that doesn't exist in entrypoint()" do
|
58
|
+
dsl_class = Class.new(DSL::Maker)
|
59
|
+
|
60
|
+
expect {
|
61
|
+
dsl_class.entrypoint(:x)
|
62
|
+
}.to raise_error("'x' is not an entrypoint")
|
63
|
+
end
|
47
64
|
end
|
data/spec/multi_level_spec.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# 1. Because we're creating classes on the fly, we must fully-qualify the Boolean
|
5
5
|
# class name. If we created real classes, the context would be provided for us.
|
6
6
|
describe 'A multi-level DSL making family-trees' do
|
7
|
-
Person = Struct.new(:name, :child)
|
7
|
+
$Person = Struct.new(:name, :child)
|
8
8
|
|
9
9
|
it "can handle a simple single-level parse of a two-level DSL" do
|
10
10
|
dsl_class = Class.new(DSL::Maker) do
|
@@ -13,15 +13,15 @@ describe 'A multi-level DSL making family-trees' do
|
|
13
13
|
:child => generate_dsl({
|
14
14
|
:name => String,
|
15
15
|
}) {
|
16
|
-
Person.new(name)
|
16
|
+
$Person.new(name)
|
17
17
|
},
|
18
18
|
}) do
|
19
|
-
Person.new(name, child)
|
19
|
+
$Person.new(name, child)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
person = dsl_class.parse_dsl('person { name "Tom" }')
|
24
|
-
expect(person).to be_instance_of(Person)
|
24
|
+
expect(person).to be_instance_of($Person)
|
25
25
|
expect(person.name).to eq('Tom')
|
26
26
|
expect(person.child).to be_nil
|
27
27
|
end
|
@@ -33,10 +33,10 @@ describe 'A multi-level DSL making family-trees' do
|
|
33
33
|
:child => generate_dsl({
|
34
34
|
:name => String,
|
35
35
|
}) {
|
36
|
-
Person.new(name, nil)
|
36
|
+
$Person.new(name, nil)
|
37
37
|
},
|
38
38
|
}) do
|
39
|
-
Person.new(name, child)
|
39
|
+
$Person.new(name, child)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -48,9 +48,9 @@ describe 'A multi-level DSL making family-trees' do
|
|
48
48
|
}
|
49
49
|
}
|
50
50
|
")
|
51
|
-
expect(person).to be_instance_of(Person)
|
51
|
+
expect(person).to be_instance_of($Person)
|
52
52
|
expect(person.name).to eq('Tom')
|
53
|
-
expect(person.child).to be_instance_of(Person)
|
53
|
+
expect(person.child).to be_instance_of($Person)
|
54
54
|
expect(person.child.name).to eq('Bill')
|
55
55
|
end
|
56
56
|
|
@@ -63,13 +63,13 @@ describe 'A multi-level DSL making family-trees' do
|
|
63
63
|
:child => generate_dsl({
|
64
64
|
:name => String,
|
65
65
|
}) {
|
66
|
-
Person.new(name, nil)
|
66
|
+
$Person.new(name, nil)
|
67
67
|
},
|
68
68
|
}) {
|
69
|
-
Person.new(name, child)
|
69
|
+
$Person.new(name, child)
|
70
70
|
},
|
71
71
|
}) do
|
72
|
-
Person.new(name, child)
|
72
|
+
$Person.new(name, child)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -84,11 +84,11 @@ describe 'A multi-level DSL making family-trees' do
|
|
84
84
|
}
|
85
85
|
}
|
86
86
|
")
|
87
|
-
expect(person).to be_instance_of(Person)
|
87
|
+
expect(person).to be_instance_of($Person)
|
88
88
|
expect(person.name).to eq('Tom')
|
89
|
-
expect(person.child).to be_instance_of(Person)
|
89
|
+
expect(person.child).to be_instance_of($Person)
|
90
90
|
expect(person.child.name).to eq('Bill')
|
91
|
-
expect(person.child.child).to be_instance_of(Person)
|
91
|
+
expect(person.child.child).to be_instance_of($Person)
|
92
92
|
expect(person.child.child.name).to eq('Judith')
|
93
93
|
end
|
94
94
|
|
@@ -98,7 +98,7 @@ describe 'A multi-level DSL making family-trees' do
|
|
98
98
|
person_dsl = add_entrypoint(:person, {
|
99
99
|
:name => String,
|
100
100
|
}) do
|
101
|
-
Person.new(name, child)
|
101
|
+
$Person.new(name, child)
|
102
102
|
end
|
103
103
|
build_dsl_element(person_dsl, :child, person_dsl)
|
104
104
|
end
|
@@ -145,7 +145,7 @@ describe 'A multi-level DSL making family-trees' do
|
|
145
145
|
'Adam', 'Seth', 'Enos', 'Cainan', 'Mahalaleel', 'Jared',
|
146
146
|
'Enoch', 'Methuselah', 'Lamech', 'Noah', 'Shem',
|
147
147
|
].each do |name|
|
148
|
-
expect(person).to be_instance_of(Person)
|
148
|
+
expect(person).to be_instance_of($Person)
|
149
149
|
expect(person.name).to eq(name)
|
150
150
|
person = person.child
|
151
151
|
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
# This will use a DSL that defines Cars
|
1
|
+
# This will use a DSL that defines $Cars
|
2
2
|
|
3
3
|
describe "A DSL describing cars used with multiple invocations" do
|
4
|
-
Car = Struct.new(:maker)
|
5
|
-
Truck = Struct.new(:maker)
|
4
|
+
$Car = Struct.new(:maker, :wheel)
|
5
|
+
$Truck = Struct.new(:maker, :wheel)
|
6
6
|
|
7
7
|
it "returns two items in the right order" do
|
8
8
|
dsl_class = Class.new(DSL::Maker) do
|
9
9
|
add_entrypoint(:car, {
|
10
10
|
:maker => String,
|
11
11
|
}) do
|
12
|
-
Car.new(maker)
|
12
|
+
$Car.new(maker)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -19,9 +19,9 @@ describe "A DSL describing cars used with multiple invocations" do
|
|
19
19
|
")
|
20
20
|
expect(cars).to be_instance_of(Array)
|
21
21
|
expect(cars.length).to eq(2)
|
22
|
-
expect(cars[0]).to be_instance_of(Car)
|
22
|
+
expect(cars[0]).to be_instance_of($Car)
|
23
23
|
expect(cars[0].maker).to eq('Honda')
|
24
|
-
expect(cars[1]).to be_instance_of(Car)
|
24
|
+
expect(cars[1]).to be_instance_of($Car)
|
25
25
|
expect(cars[1].maker).to eq('Acura')
|
26
26
|
end
|
27
27
|
|
@@ -30,12 +30,12 @@ describe "A DSL describing cars used with multiple invocations" do
|
|
30
30
|
add_entrypoint(:car, {
|
31
31
|
:maker => String,
|
32
32
|
}) do
|
33
|
-
Car.new(maker)
|
33
|
+
$Car.new(maker)
|
34
34
|
end
|
35
35
|
add_entrypoint(:truck, {
|
36
36
|
:maker => String,
|
37
37
|
}) do
|
38
|
-
Truck.new(maker)
|
38
|
+
$Truck.new(maker)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -46,11 +46,11 @@ describe "A DSL describing cars used with multiple invocations" do
|
|
46
46
|
")
|
47
47
|
expect(vehicles).to be_instance_of(Array)
|
48
48
|
expect(vehicles.length).to eq(3)
|
49
|
-
expect(vehicles[0]).to be_instance_of(Truck)
|
49
|
+
expect(vehicles[0]).to be_instance_of($Truck)
|
50
50
|
expect(vehicles[0].maker).to eq('Ford')
|
51
|
-
expect(vehicles[1]).to be_instance_of(Car)
|
51
|
+
expect(vehicles[1]).to be_instance_of($Car)
|
52
52
|
expect(vehicles[1].maker).to eq('Honda')
|
53
|
-
expect(vehicles[2]).to be_instance_of(Truck)
|
53
|
+
expect(vehicles[2]).to be_instance_of($Truck)
|
54
54
|
expect(vehicles[2].maker).to eq('Toyota')
|
55
55
|
end
|
56
56
|
|
@@ -59,12 +59,12 @@ describe "A DSL describing cars used with multiple invocations" do
|
|
59
59
|
add_entrypoint(:car, {
|
60
60
|
:maker => String,
|
61
61
|
}) do
|
62
|
-
Car.new(maker)
|
62
|
+
$Car.new(maker)
|
63
63
|
end
|
64
64
|
add_entrypoint(:truck, {
|
65
65
|
:maker => String,
|
66
66
|
}) do
|
67
|
-
Truck.new(maker)
|
67
|
+
$Truck.new(maker)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -75,11 +75,11 @@ describe "A DSL describing cars used with multiple invocations" do
|
|
75
75
|
end
|
76
76
|
expect(vehicles).to be_instance_of(Array)
|
77
77
|
expect(vehicles.length).to eq(3)
|
78
|
-
expect(vehicles[0]).to be_instance_of(Truck)
|
78
|
+
expect(vehicles[0]).to be_instance_of($Truck)
|
79
79
|
expect(vehicles[0].maker).to eq('Ford')
|
80
|
-
expect(vehicles[1]).to be_instance_of(Car)
|
80
|
+
expect(vehicles[1]).to be_instance_of($Car)
|
81
81
|
expect(vehicles[1].maker).to eq('Honda')
|
82
|
-
expect(vehicles[2]).to be_instance_of(Truck)
|
82
|
+
expect(vehicles[2]).to be_instance_of($Truck)
|
83
83
|
expect(vehicles[2].maker).to eq('Toyota')
|
84
84
|
end
|
85
85
|
end
|
data/spec/single_level_spec.rb
CHANGED
@@ -12,10 +12,10 @@
|
|
12
12
|
# class name. If we created real classes, the context would be provided for us.
|
13
13
|
describe 'A single-level DSL for pizza' do
|
14
14
|
$toppings = [:cheese, :pepperoni, :bacon, :sauce]
|
15
|
-
Pizza = Struct.new(*$toppings)
|
15
|
+
$Pizza = Struct.new(*$toppings)
|
16
16
|
|
17
17
|
def verify_pizza(pizza, values={})
|
18
|
-
expect(pizza).to be_instance_of(Pizza)
|
18
|
+
expect(pizza).to be_instance_of($Pizza)
|
19
19
|
$toppings.each do |topping|
|
20
20
|
expect(pizza.send(topping)).to eq(values[topping])
|
21
21
|
end
|
@@ -23,7 +23,7 @@ describe 'A single-level DSL for pizza' do
|
|
23
23
|
|
24
24
|
it 'makes a blank pizza' do
|
25
25
|
dsl_class = Class.new(DSL::Maker) do
|
26
|
-
add_entrypoint(:pizza) { Pizza.new }
|
26
|
+
add_entrypoint(:pizza) { $Pizza.new }
|
27
27
|
end
|
28
28
|
|
29
29
|
pizza = dsl_class.parse_dsl('pizza')
|
@@ -36,7 +36,7 @@ describe 'A single-level DSL for pizza' do
|
|
36
36
|
add_entrypoint(:pizza, {
|
37
37
|
:cheese => DSL::Maker::Boolean,
|
38
38
|
}) do
|
39
|
-
Pizza.new(cheese, nil, nil, nil)
|
39
|
+
$Pizza.new(cheese, nil, nil, nil)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -84,7 +84,7 @@ describe 'A single-level DSL for pizza' do
|
|
84
84
|
add_entrypoint(:pizza, {
|
85
85
|
:sauce => String,
|
86
86
|
}) do
|
87
|
-
Pizza.new(nil, nil, nil, sauce)
|
87
|
+
$Pizza.new(nil, nil, nil, sauce)
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
@@ -112,7 +112,7 @@ describe 'A single-level DSL for pizza' do
|
|
112
112
|
|
113
113
|
# This is a wart - this block should be against toppings_dsl, not here.
|
114
114
|
add_entrypoint(:pizza, toppings_dsl) do
|
115
|
-
Pizza.new(cheese, pepperoni, bacon, sauce)
|
115
|
+
$Pizza.new(cheese, pepperoni, bacon, sauce)
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
@@ -143,7 +143,7 @@ describe 'A single-level DSL for pizza' do
|
|
143
143
|
|
144
144
|
# This is a wart - this block should be against toppings_dsl, not here.
|
145
145
|
add_entrypoint(:pizza, toppings_dsl) do
|
146
|
-
Pizza.new(cheese, pepperoni, bacon, sauce)
|
146
|
+
$Pizza.new(cheese, pepperoni, bacon, sauce)
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
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.
|
4
|
+
version: 0.0.3
|
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-07-
|
11
|
+
date: 2015-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: docile
|
@@ -141,6 +141,7 @@ files:
|
|
141
141
|
- lib/dsl/maker/version.rb
|
142
142
|
- on_what.rb
|
143
143
|
- spec/args_spec.rb
|
144
|
+
- spec/class_as_subdsl_spec.rb
|
144
145
|
- spec/error_spec.rb
|
145
146
|
- spec/multi_level_spec.rb
|
146
147
|
- spec/multiple_invocation_spec.rb
|
@@ -171,3 +172,4 @@ signing_key:
|
|
171
172
|
specification_version: 4
|
172
173
|
summary: Easy multi-level DSLs
|
173
174
|
test_files: []
|
175
|
+
has_rdoc:
|