dsl_compose 1.0.0 → 1.1.0
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/CHANGELOG.md +13 -0
- data/README.md +300 -3
- data/lib/dsl_compose/composer.rb +74 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/equal_to_validation.rb +25 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/format_validation.rb +25 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/greater_than_or_equal_to_validation.rb +35 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/greater_than_validation.rb +35 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/in_validation.rb +35 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/interpreter.rb +86 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/length_validation.rb +42 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/less_than_or_equal_to_validation.rb +35 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/less_than_validation.rb +35 -0
- data/lib/dsl_compose/dsl/dsl_method/argument/not_in_validation.rb +35 -0
- data/lib/dsl_compose/dsl/dsl_method/argument.rb +299 -0
- data/lib/dsl_compose/dsl/dsl_method/interpreter.rb +57 -0
- data/lib/dsl_compose/dsl/dsl_method.rb +213 -0
- data/lib/dsl_compose/dsl/interpreter.rb +52 -0
- data/lib/dsl_compose/dsl.rb +148 -0
- data/lib/dsl_compose/dsls.rb +80 -0
- data/lib/dsl_compose/interpreter/execution/method_calls/method_call.rb +155 -0
- data/lib/dsl_compose/interpreter/execution/method_calls.rb +25 -0
- data/lib/dsl_compose/interpreter/execution.rb +60 -0
- data/lib/dsl_compose/interpreter.rb +43 -0
- data/lib/dsl_compose/version.rb +2 -2
- data/lib/dsl_compose.rb +32 -4
- metadata +24 -3
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSLCompose
|
4
|
+
class DSL
|
5
|
+
class DSLMethod
|
6
|
+
class Argument
|
7
|
+
class LengthValidation
|
8
|
+
class ValidationFailedError < StandardError
|
9
|
+
def message
|
10
|
+
"The argument is invalid"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize maximum: nil, minimum: nil, is: nil
|
15
|
+
@maximum = maximum
|
16
|
+
@minimum = minimum
|
17
|
+
@is = is
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate! value
|
21
|
+
maximum = @maximum
|
22
|
+
unless maximum.nil?
|
23
|
+
raise ValidationFailedError if value.length > maximum
|
24
|
+
end
|
25
|
+
|
26
|
+
minimum = @minimum
|
27
|
+
unless minimum.nil?
|
28
|
+
raise ValidationFailedError if value.length < minimum
|
29
|
+
end
|
30
|
+
|
31
|
+
is = @is
|
32
|
+
unless is.nil?
|
33
|
+
raise ValidationFailedError if value.length != is
|
34
|
+
end
|
35
|
+
|
36
|
+
true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSLCompose
|
4
|
+
class DSL
|
5
|
+
class DSLMethod
|
6
|
+
class Argument
|
7
|
+
class LessThanOrEqualToValidation
|
8
|
+
class InvalidValueError < StandardError
|
9
|
+
def message
|
10
|
+
"The value provided to validate_greater_than must be a number"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ValidationFailedError < StandardError
|
15
|
+
def message
|
16
|
+
"The argument is invalid"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize value
|
21
|
+
unless value.is_a?(Numeric)
|
22
|
+
raise InvalidValueError
|
23
|
+
end
|
24
|
+
|
25
|
+
@value = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate! value
|
29
|
+
raise ValidationFailedError unless value <= @value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSLCompose
|
4
|
+
class DSL
|
5
|
+
class DSLMethod
|
6
|
+
class Argument
|
7
|
+
class LessThanValidation
|
8
|
+
class InvalidValueError < StandardError
|
9
|
+
def message
|
10
|
+
"The value provided to validate_greater_than must be a number"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ValidationFailedError < StandardError
|
15
|
+
def message
|
16
|
+
"The argument is invalid"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize value
|
21
|
+
unless value.is_a?(Numeric)
|
22
|
+
raise InvalidValueError
|
23
|
+
end
|
24
|
+
|
25
|
+
@value = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate! value
|
29
|
+
raise ValidationFailedError unless value < @value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSLCompose
|
4
|
+
class DSL
|
5
|
+
class DSLMethod
|
6
|
+
class Argument
|
7
|
+
class NotInValidation
|
8
|
+
class InvalidValueError < StandardError
|
9
|
+
def message
|
10
|
+
"The value provided to validate_greater_than must be a number"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ValidationFailedError < StandardError
|
15
|
+
def message
|
16
|
+
"The argument is invalid"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize values
|
21
|
+
unless values.is_a?(Array)
|
22
|
+
raise InvalidValueError
|
23
|
+
end
|
24
|
+
|
25
|
+
@values = values
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate! value
|
29
|
+
raise ValidationFailedError if @values.include?(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSLCompose
|
4
|
+
class DSL
|
5
|
+
class DSLMethod
|
6
|
+
class Argument
|
7
|
+
class ValidationIncompatibleError < StandardError
|
8
|
+
def message
|
9
|
+
"The validation is not compatible with this argument type"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ValidationAlreadyExistsError < StandardError
|
14
|
+
def message
|
15
|
+
"This validation has already been applied to this method option."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class InvalidTypeError < StandardError
|
20
|
+
def message
|
21
|
+
"Argument type must be one of :integer, :boolean, :float, :string or :symbol"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class InvalidNameError < StandardError
|
26
|
+
def message
|
27
|
+
"The option name is invalid, it must be of type symbol."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class InvalidDescriptionError < StandardError
|
32
|
+
def message
|
33
|
+
"The option description is invalid, it must be of type string and have length greater than 0."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class DescriptionAlreadyExistsError < StandardError
|
38
|
+
def message
|
39
|
+
"The description has already been set"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# The name of this Argument.
|
44
|
+
attr_reader :name
|
45
|
+
# An arguments type. This determines what kind of value can be passed when calling the
|
46
|
+
# associated DSLMethod.
|
47
|
+
# `type` should be set to either :integer, :boolean, :float, :string or :symbol
|
48
|
+
attr_reader :type
|
49
|
+
# if required, then this Argument must be provided when calling its associated DSLMethod.
|
50
|
+
attr_reader :required
|
51
|
+
# An otional description of this Attribute, if provided then it must be a string.
|
52
|
+
# The description accepts markdown and is used when generating documentation.
|
53
|
+
attr_reader :description
|
54
|
+
# Optional validations that have been applied to this Argument. When the DSL is used
|
55
|
+
# each of these validations will be checked against the value provided to
|
56
|
+
# this Argument.
|
57
|
+
attr_reader :greater_than_validation
|
58
|
+
attr_reader :greater_than_or_equal_to_validation
|
59
|
+
attr_reader :less_than_validation
|
60
|
+
attr_reader :less_than_or_equal_to_validation
|
61
|
+
attr_reader :format_validation
|
62
|
+
attr_reader :equal_to_validation
|
63
|
+
attr_reader :in_validation
|
64
|
+
attr_reader :not_in_validation
|
65
|
+
attr_reader :length_validation
|
66
|
+
|
67
|
+
# Create a new Attribute object.
|
68
|
+
#
|
69
|
+
# `name` must be a symbol.
|
70
|
+
# `required` is a boolean which determines if this Attribute must be provided when
|
71
|
+
# calling its associated DSLMethod.
|
72
|
+
# `type` can be either :integer, :boolean, :float, :string or :symbol
|
73
|
+
# `block` contains the instructions to further configure this Attribute
|
74
|
+
def initialize name, required, type, &block
|
75
|
+
if name.is_a? Symbol
|
76
|
+
@name = name
|
77
|
+
else
|
78
|
+
raise InvalidNameError
|
79
|
+
end
|
80
|
+
|
81
|
+
if type == :integer || type == :boolean || type == :float || type == :string || type == :symbol
|
82
|
+
@type = type
|
83
|
+
else
|
84
|
+
raise InvalidTypeError
|
85
|
+
end
|
86
|
+
|
87
|
+
@required = required ? true : false
|
88
|
+
|
89
|
+
# If a block was provided, then we evaluate it using a seperate
|
90
|
+
# interpreter class. We do this because the interpreter class contains
|
91
|
+
# no other methods or variables, if it was evaluated in the context of
|
92
|
+
# this class then the block would have access to all of the methods defined
|
93
|
+
# in here.
|
94
|
+
if block
|
95
|
+
Interpreter.new(self).instance_eval(&block)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Set the description for this Argument to the provided value.
|
100
|
+
#
|
101
|
+
# `description` must be a string with a length greater than 0.
|
102
|
+
# The `description` can only be set once per Argument
|
103
|
+
def set_description description
|
104
|
+
unless description.is_a?(String) && description.length > 0
|
105
|
+
raise InvalidDescriptionError
|
106
|
+
end
|
107
|
+
|
108
|
+
if has_description?
|
109
|
+
raise DescriptionAlreadyExistsError
|
110
|
+
end
|
111
|
+
|
112
|
+
@description = description
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns `true` if this DSL has a description, else false.
|
116
|
+
def has_description?
|
117
|
+
@description.nil? == false
|
118
|
+
end
|
119
|
+
|
120
|
+
# returns true if this DSLMethod is flagged as required, otherwise returns false.
|
121
|
+
def required?
|
122
|
+
@required == true
|
123
|
+
end
|
124
|
+
|
125
|
+
# returns true if this DSLMethod is flagged as optional, otherwise returns false.
|
126
|
+
def optional?
|
127
|
+
@required == false
|
128
|
+
end
|
129
|
+
|
130
|
+
def validate_greater_than value
|
131
|
+
if @greater_than_validation
|
132
|
+
raise ValidationAlreadyExistsError
|
133
|
+
end
|
134
|
+
|
135
|
+
unless @type == :integer || @type == :float
|
136
|
+
raise ValidationIncompatibleError
|
137
|
+
end
|
138
|
+
|
139
|
+
@greater_than_validation = GreaterThanValidation.new value
|
140
|
+
end
|
141
|
+
|
142
|
+
def validate_greater_than_or_equal_to value
|
143
|
+
if @greater_than_or_equal_to_validation
|
144
|
+
raise ValidationAlreadyExistsError
|
145
|
+
end
|
146
|
+
|
147
|
+
unless value.is_a?(Numeric)
|
148
|
+
raise ValidationInvalidArgumentError
|
149
|
+
end
|
150
|
+
|
151
|
+
unless @type == :integer || @type == :float
|
152
|
+
raise ValidationIncompatibleError
|
153
|
+
end
|
154
|
+
|
155
|
+
@greater_than_or_equal_to_validation = GreaterThanOrEqualToValidation.new value
|
156
|
+
end
|
157
|
+
|
158
|
+
def validate_less_than value
|
159
|
+
if @less_than_validation
|
160
|
+
raise ValidationAlreadyExistsError
|
161
|
+
end
|
162
|
+
|
163
|
+
unless value.is_a?(Numeric)
|
164
|
+
raise ValidationInvalidArgumentError
|
165
|
+
end
|
166
|
+
|
167
|
+
unless @type == :integer || @type == :float
|
168
|
+
raise ValidationIncompatibleError
|
169
|
+
end
|
170
|
+
|
171
|
+
@less_than_validation = LessThanValidation.new value
|
172
|
+
end
|
173
|
+
|
174
|
+
def validate_less_than_or_equal_to value
|
175
|
+
if @less_than_or_equal_to_validation
|
176
|
+
raise ValidationAlreadyExistsError
|
177
|
+
end
|
178
|
+
|
179
|
+
unless value.is_a?(Numeric)
|
180
|
+
raise ValidationInvalidArgumentError
|
181
|
+
end
|
182
|
+
|
183
|
+
unless @type == :integer || @type == :float
|
184
|
+
raise ValidationIncompatibleError
|
185
|
+
end
|
186
|
+
|
187
|
+
@less_than_or_equal_to_validation = LessThanOrEqualToValidation.new value
|
188
|
+
end
|
189
|
+
|
190
|
+
def validate_format regexp
|
191
|
+
if @format_validation
|
192
|
+
raise ValidationAlreadyExistsError
|
193
|
+
end
|
194
|
+
|
195
|
+
unless regexp.is_a? Regexp
|
196
|
+
raise ValidationInvalidArgumentError
|
197
|
+
end
|
198
|
+
|
199
|
+
unless @type == :string || @type == :symbol
|
200
|
+
raise ValidationIncompatibleError
|
201
|
+
end
|
202
|
+
@format_validation = FormatValidation.new regexp
|
203
|
+
end
|
204
|
+
|
205
|
+
def validate_equal_to value
|
206
|
+
if @equal_to_validation
|
207
|
+
raise ValidationAlreadyExistsError
|
208
|
+
end
|
209
|
+
|
210
|
+
unless @type == :integer || @type == :float || @type == :string || @type == :symbol || @type == :boolean
|
211
|
+
raise ValidationIncompatibleError
|
212
|
+
end
|
213
|
+
|
214
|
+
@equal_to_validation = EqualToValidation.new value
|
215
|
+
end
|
216
|
+
|
217
|
+
def validate_in values
|
218
|
+
if @in_validation
|
219
|
+
raise ValidationAlreadyExistsError
|
220
|
+
end
|
221
|
+
|
222
|
+
unless values.is_a? Array
|
223
|
+
raise ValidationInvalidArgumentError
|
224
|
+
end
|
225
|
+
|
226
|
+
unless @type == :integer || @type == :float || @type == :string || @type == :symbol
|
227
|
+
raise ValidationIncompatibleError
|
228
|
+
end
|
229
|
+
|
230
|
+
@in_validation = InValidation.new values
|
231
|
+
end
|
232
|
+
|
233
|
+
def validate_not_in values
|
234
|
+
if @not_in_validation
|
235
|
+
raise ValidationAlreadyExistsError
|
236
|
+
end
|
237
|
+
|
238
|
+
unless values.is_a? Array
|
239
|
+
raise ValidationInvalidArgumentError
|
240
|
+
end
|
241
|
+
|
242
|
+
unless @type == :integer || @type == :float || @type == :string || @type == :symbol
|
243
|
+
raise ValidationIncompatibleError
|
244
|
+
end
|
245
|
+
|
246
|
+
@not_in_validation = NotInValidation.new values
|
247
|
+
end
|
248
|
+
|
249
|
+
def validate_length maximum: nil, minimum: nil, is: nil
|
250
|
+
if @length_validation
|
251
|
+
raise ValidationAlreadyExistsError
|
252
|
+
end
|
253
|
+
|
254
|
+
unless @type == :string || @type == :symbol
|
255
|
+
raise ValidationIncompatibleError
|
256
|
+
end
|
257
|
+
|
258
|
+
@length_validation = LengthValidation.new(maximum: maximum, minimum: minimum, is: is)
|
259
|
+
end
|
260
|
+
|
261
|
+
# returns true if every provided integer validation also returns true
|
262
|
+
def validate_integer! value
|
263
|
+
(greater_than_validation.nil? || greater_than_validation.validate!(value)) &&
|
264
|
+
(greater_than_or_equal_to_validation.nil? || greater_than_or_equal_to_validation.validate!(value)) &&
|
265
|
+
(less_than_validation.nil? || less_than_validation.validate!(value)) &&
|
266
|
+
(less_than_or_equal_to_validation.nil? || less_than_or_equal_to_validation.validate!(value)) &&
|
267
|
+
(format_validation.nil? || format_validation.validate!(value)) &&
|
268
|
+
(equal_to_validation.nil? || equal_to_validation.validate!(value)) &&
|
269
|
+
(in_validation.nil? || in_validation.validate!(value)) &&
|
270
|
+
(not_in_validation.nil? || not_in_validation.validate!(value)) &&
|
271
|
+
(length_validation.nil? || length_validation.validate!(value))
|
272
|
+
end
|
273
|
+
|
274
|
+
# returns true if every provided symbol validation also returns true
|
275
|
+
def validate_symbol! value
|
276
|
+
(format_validation.nil? || format_validation.validate!(value)) &&
|
277
|
+
(equal_to_validation.nil? || equal_to_validation.validate!(value)) &&
|
278
|
+
(in_validation.nil? || in_validation.validate!(value)) &&
|
279
|
+
(not_in_validation.nil? || not_in_validation.validate!(value)) &&
|
280
|
+
(length_validation.nil? || length_validation.validate!(value))
|
281
|
+
end
|
282
|
+
|
283
|
+
# returns true if every provided string validation also returns true
|
284
|
+
def validate_string! value
|
285
|
+
(format_validation.nil? || format_validation.validate!(value)) &&
|
286
|
+
(equal_to_validation.nil? || equal_to_validation.validate!(value)) &&
|
287
|
+
(in_validation.nil? || in_validation.validate!(value)) &&
|
288
|
+
(not_in_validation.nil? || not_in_validation.validate!(value)) &&
|
289
|
+
(length_validation.nil? || length_validation.validate!(value))
|
290
|
+
end
|
291
|
+
|
292
|
+
# returns true if every provided boolean validation also returns true
|
293
|
+
def validate_boolean! value
|
294
|
+
(equal_to_validation.nil? || equal_to_validation.validate!(value))
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSLCompose
|
4
|
+
class DSL
|
5
|
+
class DSLMethod
|
6
|
+
# This class is reponsible for parsing and executing method definitions
|
7
|
+
# within our internal DSL. These method definitions determine what methods
|
8
|
+
# will be available within our new dynamic DSL.
|
9
|
+
#
|
10
|
+
# This class is instantaited by the DSLCompose::DSL::DSLMethod class and the method definition
|
11
|
+
# part of our internal DSL is evaluated by passing a block to `instance_eval` on this class.
|
12
|
+
#
|
13
|
+
# An example of our internal DSL which includes a complex method definition:
|
14
|
+
# define_dsl :my_dsl do
|
15
|
+
# add_method :my_method, required: true do
|
16
|
+
# description "Description of my method"
|
17
|
+
# optional :my_optional_argument, :string do
|
18
|
+
# # ...
|
19
|
+
# end
|
20
|
+
# optional :my_optional_arg, String
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
class Interpreter
|
24
|
+
def initialize dsl_method
|
25
|
+
@dsl_method = dsl_method
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# sets the description of the DSLMethod
|
31
|
+
def description description
|
32
|
+
@dsl_method.set_description description
|
33
|
+
end
|
34
|
+
|
35
|
+
# adds a new optional argument to the DSLMethod
|
36
|
+
#
|
37
|
+
# name must be a symbol
|
38
|
+
# `type` can be either :integer, :boolean, :float, :string or :symbol
|
39
|
+
# `block` contains the argument definition and will be evaluated seperately
|
40
|
+
# by the DSLMethod::Argument::Interpreter
|
41
|
+
def optional name, type, &block
|
42
|
+
@dsl_method.add_argument name, false, type, &block
|
43
|
+
end
|
44
|
+
|
45
|
+
# adds a new required argument to the DSLMethod
|
46
|
+
#
|
47
|
+
# name must be a symbol
|
48
|
+
# `type` can be either :integer, :boolean, :float, :string or :symbol
|
49
|
+
# `block` contains the argument definition and will be evaluated seperately
|
50
|
+
# by the DSLMethod::Argument::Interpreter
|
51
|
+
def requires name, type, &block
|
52
|
+
@dsl_method.add_argument name, true, type, &block
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|