dsl_compose 2.12.0 → 2.13.1

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
  SHA256:
3
- metadata.gz: 31077b216dc51cdf2addc2bb7d094ca58d7cb90ed7ff82897712c3a46b709e10
4
- data.tar.gz: 51d663846f488abdd48a57eaf643e8d89bc9cd5db5d8ca4d4914c610debd2ca9
3
+ metadata.gz: 117789e8395652f4823ad048b258d2a683b65328d5817788b9d3d3d7bc377c8b
4
+ data.tar.gz: d4ad4b7a66de0cfd143006e4c9984bef0ce1c29e6e18b86a0621810cb2d11edb
5
5
  SHA512:
6
- metadata.gz: fc5cbde44a97a3fb2920c7e9b4bfb669ba535168e09edb68c1597ad80a2bc41aaa61aaa52c7aea233ce740f8304f6a65691d0a92072fc40ebdabb5277f6617f2
7
- data.tar.gz: 9f26a35cf368934b91967768870f1c863615746d12790a1334659ee852faab53b6dabc9182a13fe74d525dbefb2f8194a8ff83454ede48d935e9651058036af3
6
+ metadata.gz: dbcf361a908dcd619664f12e50299f80092d5e2f4e8efb4f53320b2d13c3ca30ef334e429fe1a977fb899c0878f2dd26a30d9b067b74da22198eb2372984d2ad
7
+ data.tar.gz: 9e932a4d10693634bc25532d9d625ad1939f58c975bf90a0f4a0f1714586bdce5dc1650cf48cbfaa0655c56fbaa341fd27731953e4e3fe74fbefd63619fac6ad
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.13.1](https://github.com/craigulliott/dsl_compose/compare/v2.13.0...v2.13.1) (2023-09-05)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * fixed a nil value in error message caused by overwriting method argument ([dd7848b](https://github.com/craigulliott/dsl_compose/commit/dd7848b3861bff6176c8326f6784fb29f1ba2fdd))
9
+
10
+ ## [2.13.0](https://github.com/craigulliott/dsl_compose/compare/v2.12.0...v2.13.0) (2023-09-04)
11
+
12
+
13
+ ### Features
14
+
15
+ * optionally mark required arguments as keyword arguments ([9a1c901](https://github.com/craigulliott/dsl_compose/commit/9a1c90169fb36c550b0577034823579062120647))
16
+
3
17
  ## [2.12.0](https://github.com/craigulliott/dsl_compose/compare/v2.11.0...v2.12.0) (2023-09-02)
4
18
 
5
19
 
data/README.md CHANGED
@@ -114,6 +114,16 @@ class Foo
114
114
  validate_greater_than 0
115
115
  end
116
116
 
117
+ # Required arguments for both DSLs and DSL methods are assumed to be standard ruby
118
+ # arguments by default, but can be declared as keyword arguments by passing `kwarg: true`.
119
+ # This is useful because sometimes keyword arguments can make your DSL more readable. This
120
+ # option does not exist for optional arguments, because optional arguments are always kwargs.
121
+ requires :required_keyword_argument, :symbol, kwarg: true do
122
+ # You should provide descriptions for your arguments. These descriptions will
123
+ # be used when generating your documentation. This description supports markdown
124
+ description "A description of the first argument for this method"
125
+ end
126
+
117
127
  # All optional and required arguments can optionally accept an array of values. When using
118
128
  # your final DSL, a single item can be provided but will automatically be converted to an
119
129
  # array of items. All items in the array must be of the expected type.
@@ -13,6 +13,9 @@ module DSLCompose
13
13
  class InvalidTypeError < StandardError
14
14
  end
15
15
 
16
+ class ImpossibleKwargError < StandardError
17
+ end
18
+
16
19
  class InvalidNameError < StandardError
17
20
  end
18
21
 
@@ -42,6 +45,10 @@ module DSLCompose
42
45
  attr_reader :type
43
46
  # if required, then this Argument must be provided when calling its associated DSLMethod.
44
47
  attr_reader :required
48
+ # If true, then this argument must be provided as a keyword argument, this is only appropriate for
49
+ # required arguments, as optional arguments are always passed as keywork arguments.
50
+ # arguments.
51
+ attr_reader :kwarg
45
52
  # If true, then this argument accepts an array of values. It will also accept a single value,
46
53
  # but that single value will be automatically converted to an array
47
54
  attr_reader :array
@@ -71,9 +78,10 @@ module DSLCompose
71
78
  # `name` must be a symbol.
72
79
  # `required` is a boolean which determines if this Attribute must be provided when
73
80
  # calling its associated DSLMethod.
81
+ # `kwarg` is a boolean which determines if a required Attribute must be provided as a keyword argument.
74
82
  # `type` can be either :integer, :boolean, :float, :string or :symbol
75
83
  # `block` contains the instructions to further configure this Attribute
76
- def initialize name, required, type, array: false, &block
84
+ def initialize name, required, kwarg, type, array: false, &block
77
85
  if name.is_a? Symbol
78
86
 
79
87
  if RESERVED_ARGUMENT_NAMES.include? name
@@ -93,6 +101,12 @@ module DSLCompose
93
101
 
94
102
  @required = required ? true : false
95
103
 
104
+ if @required == false && kwarg == true
105
+ raise ImpossibleKwargError, "Optional arguments must always be provided as keyword arguments. The argument `#{name}` can not be both required: false and kwarg: true."
106
+ end
107
+
108
+ @kwarg = kwarg ? true : false
109
+
96
110
  @array = array ? true : false
97
111
 
98
112
  # If a block was provided, then we evaluate it using a seperate
@@ -85,8 +85,9 @@ module DSLCompose
85
85
  #
86
86
  # Argument `name` must be unique within the DSLMethod.
87
87
  # `required` must be a boolean, and determines if this argument will be required
88
+ # `kwarg` is a boolean which determines if a required Attribute must be provided as a keyword argument.
88
89
  # or optional on the method which is exposed in our DSL.
89
- def add_argument name, required, type, array: false, &block
90
+ def add_argument name, required, kwarg, type, array: false, &block
90
91
  if @arguments.key? name
91
92
  raise ArgumentAlreadyExistsError, "An argument with the name `#{name}` already exists for this DSL method"
92
93
  end
@@ -96,7 +97,7 @@ module DSLCompose
96
97
  raise ArgumentOrderingError, "Required arguments can not be added after optional ones"
97
98
  end
98
99
 
99
- @arguments[name] = Argument.new(name, required, type, array: array, &block)
100
+ @arguments[name] = Argument.new(name, required, kwarg, type, array: array, &block)
100
101
  end
101
102
  end
102
103
  end
@@ -39,17 +39,19 @@ module DSLCompose
39
39
  # `block` contains the argument definition and will be evaluated seperately
40
40
  # by the Argument::Interpreter
41
41
  def optional name, type, array: false, &block
42
- @dsl_method.arguments.add_argument name, false, type, array: array, &block
42
+ @dsl_method.arguments.add_argument name, false, false, type, array: array, &block
43
43
  end
44
44
 
45
45
  # adds a new required argument to the DSLMethod
46
46
  #
47
47
  # name must be a symbol
48
+ # `kwarg` is a boolean which determines if a required Attribute must be provided as a keyword argument.
49
+ # `array` is a boolean which determines if this argument will accept an array of the given type or a single item
48
50
  # `type` can be either :integer, :boolean, :float, :string or :symbol
49
51
  # `block` contains the argument definition and will be evaluated seperately
50
52
  # by the Argument::Interpreter
51
- def requires name, type, array: false, &block
52
- @dsl_method.arguments.add_argument name, true, type, array: array, &block
53
+ def requires name, type, kwarg: false, array: false, &block
54
+ @dsl_method.arguments.add_argument name, true, kwarg, type, array: array, &block
53
55
  end
54
56
 
55
57
  # executes the shared configuration block with the given name within the
@@ -66,17 +66,19 @@ module DSLCompose
66
66
  # `block` contains the argument definition and will be evaluated seperately
67
67
  # by the Argument::Interpreter
68
68
  def optional name, type, array: false, &block
69
- @dsl.arguments.add_argument name, false, type, array: array, &block
69
+ @dsl.arguments.add_argument name, false, false, type, array: array, &block
70
70
  end
71
71
 
72
72
  # adds a new required argument to the DSLMethod
73
73
  #
74
74
  # name must be a symbol
75
+ # `kwarg` is a boolean which determines if a required Attribute must be provided as a keyword argument.
76
+ # `array` is a boolean which determines if this argument will accept an array of the given type or a single item
75
77
  # `type` can be either :integer, :boolean, :float, :string, :symbol, :class or :object
76
78
  # `block` contains the argument definition and will be evaluated seperately
77
79
  # by the Argument::Interpreter
78
- def requires name, type, array: false, &block
79
- @dsl.arguments.add_argument name, true, type, array: array, &block
80
+ def requires name, type, kwarg: false, array: false, &block
81
+ @dsl.arguments.add_argument name, true, kwarg, type, array: array, &block
80
82
  end
81
83
 
82
84
  # executes the shared configuration block with the given name within the
@@ -25,18 +25,38 @@ module DSLCompose
25
25
  @arguments = {}
26
26
 
27
27
  required_argument_count = arguments.required_arguments.count
28
+ required_non_kwarg_argument_count = arguments.required_arguments.count { |a| !a.kwarg }
28
29
  has_optional_arguments = arguments.optional_arguments.any?
29
30
 
30
- # the first N args, where N = required_argument_count, are the
31
+ # the first N args, where N = required_non_kwarg_argument_count, are the
31
32
  # provided required arguments
32
- required_args = args.slice(0, required_argument_count)
33
- # the optional arg which comes next is the hash which represents
34
- # all the optional arguments
35
- optional_arg = args[required_argument_count]
33
+ required_args = args.slice(0, required_non_kwarg_argument_count)
34
+
35
+ # the final argument is the object which contains all the keyword args (these keyword
36
+ # args could be optional or required)
37
+ all_kwargs = args[required_non_kwarg_argument_count]
38
+
39
+ # process all the required arguments which are kwargs
40
+ required_kwargs = arguments.required_arguments.filter { |a| a.kwarg }
41
+ required_kwargs.each do |required_kwarg|
42
+ if all_kwargs.key? required_kwarg.name
43
+ # add the keyword argument to the required args
44
+ required_args << all_kwargs[required_kwarg.name]
45
+ # delete the required kwarg from the kwargs hash, so that we are
46
+ # left with only the optional args
47
+ all_kwargs.delete required_kwarg.name
48
+ else
49
+ raise MissingRequiredArgumentsError, "The required kwarg `#{required_kwarg.name}` was not provided"
50
+ end
51
+ end
52
+
53
+ # at this point, all_kwargs should be a hash which only represents
54
+ # the optional arguments
55
+ optional_arg = all_kwargs
36
56
 
37
57
  # assert that a value is provided for every required argument
38
58
  unless required_argument_count == required_args.count
39
- raise MissingRequiredArgumentsError, "This requires #{required_argument_count} arguments, but only #{required_args.count} were provided"
59
+ raise MissingRequiredArgumentsError, "This requires #{required_non_kwarg_argument_count} arguments, but only #{required_args.count} were provided"
40
60
  end
41
61
 
42
62
  # assert that too many arguments have not been provided
@@ -61,7 +81,7 @@ module DSLCompose
61
81
  end
62
82
 
63
83
  # asset that, if provided, then the optional argument (always the last one) is a Hash
64
- if has_optional_arguments && optional_arg.nil? === false
84
+ if has_optional_arguments && !optional_arg.nil?
65
85
  unless optional_arg.is_a? Hash
66
86
  raise OptionalArgumentsShouldBeHashError, "If provided, then the optional arguments must be last, and be represented as a Hash"
67
87
  end
@@ -165,13 +185,13 @@ module DSLCompose
165
185
  # to the corresponding class, logic which doesn't happen here in case the class doesnt
166
186
  # exist yet)
167
187
  required_arg_value = if required_argument.type == :class
168
- if args[i].is_a?(Array)
169
- args[i].map { |v| ClassCoerce.new v }
188
+ if required_args[i].is_a?(Array)
189
+ required_args[i].map { |v| ClassCoerce.new v }
170
190
  else
171
- ClassCoerce.new args[i]
191
+ ClassCoerce.new required_args[i]
172
192
  end
173
193
  else
174
- args[i]
194
+ required_args[i]
175
195
  end
176
196
 
177
197
  if required_arg_value.is_a?(Array) && !required_argument.array
@@ -24,24 +24,25 @@ module DSLCompose
24
24
  # Move up through this classes ancestors until we find the class which defined
25
25
  # the DSL with the provided name. When we reach the top of the ancestor chain we
26
26
  # exit the loop.
27
- while klass
27
+ k = klass
28
+ while k
28
29
  # if we find a DSL with this name, then store a reference to the DSL and the
29
30
  # ancestor class where it was defined
30
- if DSLs.class_dsl_exists?(klass, dsl_name)
31
- @dsl = DSLs.class_dsl(klass, dsl_name)
32
- @dsl_defining_class = klass
31
+ if DSLs.class_dsl_exists?(k, dsl_name)
32
+ @dsl = DSLs.class_dsl(k, dsl_name)
33
+ @dsl_defining_class = k
33
34
  # stop once we find the DSL
34
35
  break
35
36
  end
36
37
 
37
38
  # the DSL was not found here, so traverse up the provided classes hierachy
38
39
  # and keep looking for where this DSL was initially defined
39
- klass = klass.superclass
40
+ k = k.superclass
40
41
  end
41
42
 
42
43
  # if no DSL was found, then raise an error
43
44
  if @dsl.nil? && @dsl_defining_class.nil?
44
- raise DSLNotFound, "No DSL named `#{dsl_name}` was found for class `#{klass}`"
45
+ raise DSLNotFound, "No DSL named `#{dsl_name}` was found for class `#{@klass}`"
45
46
  end
46
47
  end
47
48
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DSLCompose
4
- VERSION = "2.12.0"
4
+ VERSION = "2.13.1"
5
5
  end
@@ -9,6 +9,7 @@ module DSLCompose
9
9
  attr_reader name: Symbol
10
10
  attr_reader type: argument_type
11
11
  attr_reader required: bool
12
+ attr_reader kwarg: bool
12
13
  attr_reader array: bool
13
14
  attr_reader description: String
14
15
 
@@ -27,7 +28,7 @@ module DSLCompose
27
28
  attr_reader length_validation: LengthValidation
28
29
  attr_reader is_a_validation: IsAValidation
29
30
 
30
- def initialize: (Symbol name, bool required, argument_type `type`, ?array: bool) -> void
31
+ def initialize: (Symbol name, bool required, bool kwarg, argument_type `type`, ?array: bool) -> void
31
32
  def set_description: (String description) -> void
32
33
  def has_description?: () -> bool
33
34
  def required?: -> bool
@@ -12,7 +12,7 @@ module DSLCompose
12
12
  def optional_argument: (Symbol name) -> Argument
13
13
  def required_argument: (Symbol name) -> Argument
14
14
  def has_argument?: (Symbol name) -> bool
15
- def add_argument: (Symbol name, bool required, argument_type `type`, ?array: bool) -> Argument
15
+ def add_argument: (Symbol name, bool required, bool kwarg, argument_type `type`, ?array: bool) -> Argument
16
16
 
17
17
  class ArgumentDoesNotExistError < StandardError
18
18
  end
@@ -11,7 +11,7 @@ module DSLCompose
11
11
  private
12
12
  def description: (String description) -> void
13
13
  def optional: (Symbol name, argument_type `type`, ?array: bool) -> void
14
- def requires: (Symbol name, argument_type `type`, ?array: bool) -> void
14
+ def requires: (Symbol name, argument_type `type`, ?kwarg: bool, ?array: bool) -> void
15
15
  end
16
16
  end
17
17
  end
@@ -14,7 +14,7 @@ module DSLCompose
14
14
  def add_method: (Symbol name, ?required: nil) -> void
15
15
  def add_unique_method: (Symbol name, ?required: nil) -> void
16
16
  def optional: (Symbol name, argument_type `type`, ?array: bool) -> void
17
- def requires: (Symbol name, argument_type `type`, ?array: bool) -> void
17
+ def requires: (Symbol name, argument_type `type`, ?kwarg: bool, ?array: bool) -> void
18
18
  end
19
19
  end
20
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dsl_compose
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.13.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Craig Ulliott
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-02 00:00:00.000000000 Z
11
+ date: 2023-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: class_spec_helper