graphlyte 0.3.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphlyte/data.rb +68 -0
  3. data/lib/graphlyte/document.rb +131 -0
  4. data/lib/graphlyte/dsl.rb +86 -0
  5. data/lib/graphlyte/editor.rb +288 -0
  6. data/lib/graphlyte/editors/annotate_types.rb +75 -0
  7. data/lib/graphlyte/editors/canonicalize.rb +26 -0
  8. data/lib/graphlyte/editors/collect_variable_references.rb +36 -0
  9. data/lib/graphlyte/editors/infer_signature.rb +36 -0
  10. data/lib/graphlyte/editors/inline_fragments.rb +37 -0
  11. data/lib/graphlyte/editors/remove_unneeded_spreads.rb +64 -0
  12. data/lib/graphlyte/editors/select_operation.rb +116 -0
  13. data/lib/graphlyte/editors/with_variables.rb +106 -0
  14. data/lib/graphlyte/errors.rb +33 -0
  15. data/lib/graphlyte/lexer.rb +392 -0
  16. data/lib/graphlyte/lexing/location.rb +43 -0
  17. data/lib/graphlyte/lexing/token.rb +31 -0
  18. data/lib/graphlyte/parser.rb +269 -0
  19. data/lib/graphlyte/parsing/backtracking_parser.rb +160 -0
  20. data/lib/graphlyte/refinements/string_refinement.rb +14 -8
  21. data/lib/graphlyte/refinements/syntax_refinements.rb +62 -0
  22. data/lib/graphlyte/schema.rb +165 -0
  23. data/lib/graphlyte/schema_query.rb +82 -65
  24. data/lib/graphlyte/selection_builder.rb +189 -0
  25. data/lib/graphlyte/selector.rb +75 -0
  26. data/lib/graphlyte/serializer.rb +223 -0
  27. data/lib/graphlyte/syntax.rb +369 -0
  28. data/lib/graphlyte.rb +24 -42
  29. metadata +88 -19
  30. data/lib/graphlyte/arguments/set.rb +0 -94
  31. data/lib/graphlyte/arguments/value.rb +0 -42
  32. data/lib/graphlyte/arguments/value_literal.rb +0 -17
  33. data/lib/graphlyte/builder.rb +0 -59
  34. data/lib/graphlyte/directive.rb +0 -25
  35. data/lib/graphlyte/field.rb +0 -65
  36. data/lib/graphlyte/fieldset.rb +0 -36
  37. data/lib/graphlyte/fragment.rb +0 -17
  38. data/lib/graphlyte/inline_fragment.rb +0 -29
  39. data/lib/graphlyte/query.rb +0 -150
  40. data/lib/graphlyte/schema/parser.rb +0 -687
  41. data/lib/graphlyte/schema/types/base.rb +0 -54
  42. data/lib/graphlyte/types.rb +0 -9
@@ -0,0 +1,369 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './errors'
4
+ require_relative './data'
5
+ require_relative './refinements/syntax_refinements'
6
+
7
+ module Graphlyte
8
+ module Syntax
9
+ # An operation represents a top-level executable definition of
10
+ # a query, mutation or a subscription.
11
+ # See: https://spec.graphql.org/October2021/#sec-Language.Operations
12
+ class Operation < Graphlyte::Data
13
+ attr_reader :type
14
+ attr_accessor :name, :variables, :directives, :selection
15
+
16
+ def initialize(type: nil, **args)
17
+ super(**args)
18
+ self.type = type if type
19
+ end
20
+
21
+ def executable?
22
+ true
23
+ end
24
+
25
+ def valid?
26
+ !selection.empty? && valid_type?
27
+ end
28
+
29
+ def valid_type?
30
+ %i[query mutation subscription].include?(type)
31
+ end
32
+
33
+ def type=(value)
34
+ @type = value
35
+ return if valid_type?
36
+
37
+ raise IllegalValue,
38
+ "Illegal value: #{value.inspect}. Expected query, mutation or subscription"
39
+ end
40
+ end
41
+
42
+ # An argument to a Field
43
+ # See: https://spec.graphql.org/October2021/#sec-Language.Arguments
44
+ class Argument < Graphlyte::Data
45
+ attr_accessor :name, :value
46
+
47
+ def initialize(name = nil, value = nil, **kwargs)
48
+ super(**kwargs)
49
+ @name = name if name
50
+ @value = value if value
51
+ end
52
+ end
53
+
54
+ Directive = Struct.new(:name, :arguments)
55
+
56
+ # Clases that have fragment names may include this module
57
+ module HasFragmentName
58
+ def self.included(mod)
59
+ mod.attr_reader :name
60
+ end
61
+
62
+ def name=(value)
63
+ raise IllegalValue, 'Not a legal fragment name' if value == 'on'
64
+
65
+ @name = value
66
+ end
67
+ end
68
+
69
+ # A discrete piece of information in the Graph
70
+ # See: https://spec.graphql.org/October2021/#sec-Language.Fields
71
+ class Field < Graphlyte::Data
72
+ attr_accessor :as, :name, :arguments, :directives, :selection
73
+ # type is special: it is not part of the serialized Query, but
74
+ # inferred from the schema. See: editors/annotate_types.rb
75
+ attr_accessor :type
76
+
77
+ def initialize(**kwargs)
78
+ super
79
+ @arguments ||= []
80
+ @directives ||= []
81
+ @selection ||= []
82
+ end
83
+
84
+ def simple?
85
+ as.nil? && arguments.empty? && directives.empty? && selection.empty?
86
+ end
87
+ end
88
+
89
+ # A reference to the use of a Fragment
90
+ # See: https://spec.graphql.org/October2021/#FragmentSpread
91
+ class FragmentSpread < Graphlyte::Data
92
+ include HasFragmentName
93
+
94
+ attr_accessor :directives
95
+
96
+ def simple?
97
+ false
98
+ end
99
+ end
100
+
101
+ InlineFragment = Struct.new(:type_name, :directives, :selection) do
102
+ def simple?
103
+ false
104
+ end
105
+ end
106
+
107
+ # A definition of a re-usable chunk of an operation
108
+ # See: https://spec.graphql.org/October2021/#sec-Language.Fragments
109
+ class Fragment < Graphlyte::Data
110
+ include HasFragmentName
111
+
112
+ attr_accessor :type_name, :directives, :selection
113
+
114
+ def initialize(**kwargs)
115
+ super
116
+ @refers_to = []
117
+ end
118
+
119
+ def inline
120
+ InlineFragment.new(type_name, directives, selection)
121
+ end
122
+
123
+ def refers_to(fragment)
124
+ @refers_to << fragment
125
+ end
126
+
127
+ def required_fragments
128
+ [self] + @refers_to
129
+ end
130
+
131
+ def executable?
132
+ true
133
+ end
134
+ end
135
+
136
+ Literal = Struct.new(:value, :type, :to_s) # rubocop:disable Lint/StructNewOverride
137
+ NULL = Literal.new(nil, :NULL, 'null').freeze
138
+ TRUE = Literal.new(true, :BOOL, 'true').freeze
139
+ FALSE = Literal.new(false, :BOOL, 'false').freeze
140
+
141
+ VariableDefinition = Struct.new(:variable, :type, :default_value, :directives, keyword_init: true)
142
+
143
+ # A use of a variable in an operation or fragment
144
+ # See: https://spec.graphql.org/October2021/#Variable
145
+ class VariableReference < Graphlyte::Data
146
+ attr_accessor :variable, :inferred_type
147
+
148
+ def initialize(variable = nil, inferred_type = nil, **kwargs)
149
+ super(**kwargs)
150
+ @variable ||= variable
151
+ @inferred_type ||= inferred_type
152
+ end
153
+
154
+ def to_definition
155
+ VariableDefinition.new(variable: variable, type: inferred_type)
156
+ end
157
+
158
+ private
159
+
160
+ def state
161
+ @variable
162
+ end
163
+ end
164
+
165
+ # A reference to a type, possibly containing other types.
166
+ # See: https://spec.graphql.org/October2021/#sec-Type-References
167
+ class Type < Graphlyte::Data
168
+ attr_accessor :inner, :is_list, :non_null, :non_null_list
169
+
170
+ def initialize(name = nil, **kwargs)
171
+ super(**kwargs)
172
+ @inner ||= name
173
+ @is_list ||= false
174
+ @non_null ||= false
175
+ @non_null_list ||= false
176
+ end
177
+
178
+ # Used during value->type inference
179
+ # always non-null, because we have a value.
180
+ def self.list_of(inner)
181
+ t = new(inner)
182
+ t.is_list = true
183
+ t.non_null = true
184
+ t
185
+ end
186
+
187
+ def to_s
188
+ str = inner.to_s
189
+ str = "#{str}!" if non_null
190
+ str = "[#{str}]" if is_list
191
+ str += '!' if non_null_list
192
+
193
+ str
194
+ end
195
+
196
+ def unpack
197
+ return inner if inner.is_a?(String)
198
+
199
+ inner.unpack
200
+ end
201
+
202
+ def self.from_type_ref(type_ref)
203
+ raise ArgumentError, 'type_ref cannot be nil' if type_ref.nil?
204
+
205
+ inner = from_type_ref(type_ref.of_type) if type_ref.of_type
206
+
207
+ case type_ref.kind
208
+ when :NON_NULL
209
+ non_null(inner)
210
+ when :LIST
211
+ list_type(inner)
212
+ when :SCALAR, :OBJECT, :ENUM
213
+ raise ArgumentError, "#{type_ref.kind} cannot have inner type" if inner
214
+
215
+ new(inner: type_ref.name)
216
+ else
217
+ raise ArgumentError, "Unexpected kind: #{type_ref.kind.inspect}"
218
+ end
219
+ end
220
+
221
+ def self.list_type(inner)
222
+ raise ArgumentError, 'List types must have inner type' unless inner
223
+
224
+ new(is_list: true, inner: inner)
225
+ end
226
+
227
+ def self.non_null(inner)
228
+ raise ArgumentError, 'Non null types must have inner type' unless inner
229
+
230
+ type = new(non_null: true, inner: inner)
231
+
232
+ if inner.respond_to?(:is_list) && inner.is_list
233
+ type.is_list = true
234
+ type.inner = inner.inner
235
+ end
236
+
237
+ type
238
+ end
239
+ end
240
+
241
+ # A CONST input value
242
+ # See: https://spec.graphql.org/October2021/#sec-Input-Values
243
+ class Value < Graphlyte::Data
244
+ using Refinements::SyntaxRefinements
245
+
246
+ attr_accessor :value, :type
247
+
248
+ def initialize(value = nil, type = nil, **kwargs)
249
+ super(**kwargs)
250
+ @value = value if value
251
+ @type = type if type
252
+ @type ||= value&.type
253
+ end
254
+
255
+ def self.from_name(name)
256
+ case name
257
+ when 'true'
258
+ true.to_input_value
259
+ when 'false'
260
+ false.to_input_value
261
+ when 'null'
262
+ nil.to_input_value
263
+ else
264
+ name.to_sym.to_input_value
265
+ end
266
+ end
267
+
268
+ def inspect
269
+ "#<#{self.class.name} @type=#{type} @value=#{value.inspect}>"
270
+ end
271
+ alias to_s inspect
272
+
273
+ def eql?(other)
274
+ return true if super
275
+ return true if numeric_eql?(other)
276
+
277
+ false
278
+ end
279
+
280
+ def numeric_eql?(other)
281
+ return false unless number?
282
+ return false unless other&.number?
283
+
284
+ if floating? || other.floating?
285
+ (value.to_f - other.value.to_f) < Float::EPSILON
286
+ else
287
+ value.to_i == other.value.to_i
288
+ end
289
+ end
290
+
291
+ def floating?
292
+ return false unless number?
293
+ return true if value.is_a?(Float)
294
+ return true if value.is_a?(NumericLiteral) && value.floating?
295
+
296
+ false
297
+ end
298
+
299
+ def number?
300
+ type == :NUMBER
301
+ end
302
+
303
+ def self.from_ruby(object)
304
+ object.to_input_value
305
+ rescue NoMethodError
306
+ raise IllegalValue, object
307
+ end
308
+ end
309
+
310
+ # A representation of a GraphQL literal, preserving the text components
311
+ #
312
+ # Note: NumericLiterals are immutable.
313
+ class NumericLiteral < Graphlyte::Data
314
+ attr_reader :integer_part, :fractional_part, :exponent_part, :negated
315
+
316
+ def initialize(**kwargs)
317
+ super
318
+ @negated ||= false
319
+
320
+ raise ArgumentError, 'integer_part is required' unless @integer_part
321
+
322
+ freeze
323
+ end
324
+
325
+ def floating?
326
+ !!@fractional_part || !!@exponent_part
327
+ end
328
+
329
+ def to_s
330
+ s = "#{negated ? '-' : ''}#{integer_part}"
331
+ return s unless floating?
332
+
333
+ s << ".#{fractional_part}" if fractional_part
334
+ s << "e#{exponent_part.first}#{exponent_part.last}" if @exponent_part
335
+
336
+ s
337
+ end
338
+
339
+ def to_i
340
+ unnegate(negated, integer_part.to_i)
341
+ end
342
+
343
+ def to_f
344
+ n = to_i.to_f
345
+ n += fractional_value if fractional_part
346
+ n *= exponent_value if exponent_part
347
+
348
+ n
349
+ end
350
+
351
+ private
352
+
353
+ attr_writer :integer_part, :fractional_part, :exponent_part, :negated
354
+
355
+ def exponent_value
356
+ 10**unnegate(exponent_part.first, exponent_part.last.to_i)
357
+ end
358
+
359
+ def fractional_value
360
+ fp = unnegate(negated, fractional_part.to_i.to_f)
361
+ fp / (10**fractional_part.length)
362
+ end
363
+
364
+ def unnegate(negated, value)
365
+ value * (negated ? -1 : 1)
366
+ end
367
+ end
368
+ end
369
+ end
data/lib/graphlyte.rb CHANGED
@@ -1,54 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
1
4
  require 'json'
2
- require_relative "./graphlyte/fieldset"
3
- require_relative "./graphlyte/query"
4
- require_relative "./graphlyte/fragment"
5
- require_relative 'graphlyte/inline_fragment'
6
- require_relative "./graphlyte/schema_query"
7
- require_relative "./graphlyte/types"
8
- require_relative "./graphlyte/schema/parser"
9
5
 
6
+ require_relative './graphlyte/syntax'
7
+ require_relative './graphlyte/schema'
8
+ require_relative './graphlyte/lexer'
9
+ require_relative './graphlyte/parser'
10
+ require_relative './graphlyte/editor'
11
+ require_relative './graphlyte/serializer'
12
+ require_relative './graphlyte/selector'
13
+ require_relative './graphlyte/selection_builder'
14
+ require_relative './graphlyte/dsl'
15
+ require_relative './graphlyte/schema_query'
16
+
17
+ # A GraphQL parsing, introspection, construction and manipulation library
10
18
  module Graphlyte
11
19
  extend SchemaQuery
20
+ extend SingleForwardable
12
21
 
13
- TYPES = Types.new
14
-
15
- def self.parse(gql)
16
- Graphlyte::Schema::Parser.parse(gql)
17
- end
18
-
19
- def self.query(name = nil, &block)
20
- Query.new(name, :query, builder: build(&block))
21
- end
22
-
23
- def self.mutation(name = nil, &block)
24
- Query.new(name, :mutation, builder: build(&block))
25
- end
26
-
27
- def self.custom(name, type, &block)
28
- Query.new(name, type.to_sym, builder: build(&block))
29
- end
30
-
31
- def self.inline_fragment(model_name, &block)
32
- InlineFragment.new(model_name, builder: build(&block))
33
- end
22
+ NO_SCHEMA_DSL = Graphlyte::DSL.new
34
23
 
35
- def self.inline_directive(directive, **hargs, &block)
36
- InlineFragment.from_directive(directive, **hargs, builder: build(&block) )
37
- end
24
+ def_delegators 'Graphlyte::NO_SCHEMA_DSL', :query, :mutation, :var, :fragment
38
25
 
39
- def self.fragment(fragment_name, model_name, &block)
40
- Fragment.new(fragment_name, model_name, builder: build(&block))
41
- end
26
+ def self.parse(gql)
27
+ ts = Graphlyte::Lexer.lex(gql)
28
+ parser = Graphlyte::Parser.new(tokens: ts)
42
29
 
43
- def self.fieldset(model_name=nil, &block)
44
- Fieldset.new(model_name, builder: build(&block))
30
+ parser.query
45
31
  end
46
32
 
47
- private
48
-
49
- def self.build(&block)
50
- builder = Builder.new
51
- builder.>.instance_eval(&block)
52
- builder
33
+ def self.dsl(schema)
34
+ DSL.new(schema)
53
35
  end
54
36
  end
metadata CHANGED
@@ -1,17 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphlyte
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Gregory
8
+ - Alex Kalderimis
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2022-03-28 00:00:00.000000000 Z
12
+ date: 2022-07-19 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
- name: rspec
15
+ name: pry-byebug
15
16
  requirement: !ruby/object:Gem::Requirement
16
17
  requirements:
17
18
  - - ">="
@@ -38,33 +39,101 @@ dependencies:
38
39
  - - ">="
39
40
  - !ruby/object:Gem::Version
40
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: simplecov
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: simplecov-cobertura
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: super_diff
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
41
98
  description: craft graphql queries with ruby
42
- email: sean.christopher.gregory@gmail.com
99
+ email: alex.kalderimis@gmail.com
43
100
  executables: []
44
101
  extensions: []
45
102
  extra_rdoc_files: []
46
103
  files:
47
104
  - lib/graphlyte.rb
48
- - lib/graphlyte/arguments/set.rb
49
- - lib/graphlyte/arguments/value.rb
50
- - lib/graphlyte/arguments/value_literal.rb
51
- - lib/graphlyte/builder.rb
52
- - lib/graphlyte/directive.rb
53
- - lib/graphlyte/field.rb
54
- - lib/graphlyte/fieldset.rb
55
- - lib/graphlyte/fragment.rb
56
- - lib/graphlyte/inline_fragment.rb
57
- - lib/graphlyte/query.rb
105
+ - lib/graphlyte/data.rb
106
+ - lib/graphlyte/document.rb
107
+ - lib/graphlyte/dsl.rb
108
+ - lib/graphlyte/editor.rb
109
+ - lib/graphlyte/editors/annotate_types.rb
110
+ - lib/graphlyte/editors/canonicalize.rb
111
+ - lib/graphlyte/editors/collect_variable_references.rb
112
+ - lib/graphlyte/editors/infer_signature.rb
113
+ - lib/graphlyte/editors/inline_fragments.rb
114
+ - lib/graphlyte/editors/remove_unneeded_spreads.rb
115
+ - lib/graphlyte/editors/select_operation.rb
116
+ - lib/graphlyte/editors/with_variables.rb
117
+ - lib/graphlyte/errors.rb
118
+ - lib/graphlyte/lexer.rb
119
+ - lib/graphlyte/lexing/location.rb
120
+ - lib/graphlyte/lexing/token.rb
121
+ - lib/graphlyte/parser.rb
122
+ - lib/graphlyte/parsing/backtracking_parser.rb
58
123
  - lib/graphlyte/refinements/string_refinement.rb
59
- - lib/graphlyte/schema/parser.rb
60
- - lib/graphlyte/schema/types/base.rb
124
+ - lib/graphlyte/refinements/syntax_refinements.rb
125
+ - lib/graphlyte/schema.rb
61
126
  - lib/graphlyte/schema_query.rb
62
- - lib/graphlyte/types.rb
127
+ - lib/graphlyte/selection_builder.rb
128
+ - lib/graphlyte/selector.rb
129
+ - lib/graphlyte/serializer.rb
130
+ - lib/graphlyte/syntax.rb
63
131
  homepage: https://rubygems.org/gems/graphlyte
64
132
  licenses:
65
133
  - MIT
66
134
  metadata:
67
- source_code_uri: https://gitlab.com/seanchristophergregory/graphlyte
135
+ source_code_uri: https://gitlab.com/skinnyjames/graphlyte
136
+ rubygems_mfa_required: 'true'
68
137
  post_install_message:
69
138
  rdoc_options: []
70
139
  require_paths:
@@ -73,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
73
142
  requirements:
74
143
  - - ">="
75
144
  - !ruby/object:Gem::Version
76
- version: '0'
145
+ version: 2.7.0
77
146
  required_rubygems_version: !ruby/object:Gem::Requirement
78
147
  requirements:
79
148
  - - ">="
@@ -1,94 +0,0 @@
1
- require_relative "./value"
2
- require_relative "./../refinements/string_refinement"
3
- module Graphlyte
4
- module Arguments
5
- class Set
6
- using Refinements::StringRefinement
7
-
8
- attr_reader :values
9
-
10
- def initialize(data)
11
- raise ArgumentError, "input #{data} must be a hash" unless data.nil? || data.is_a?(Hash)
12
- @values = expand_arguments(data) unless data.nil?
13
- end
14
-
15
- def resolve_lazy_special_args(parser_special_args)
16
- @values&.each do |key, value|
17
- if value.is_a?(Set)
18
- value.resolve_lazy_special_args(parser_special_args) if value.is_a?(Set)
19
- elsif value.is_a?(Array)
20
- value.each do |it|
21
- it.refresh(parser_special_args) if it.is_a?(Value)
22
- it.resolve_lazy_special_args(parser_special_args) if it.is_a?(Set)
23
- end
24
- else
25
- value.refresh(parser_special_args)
26
- end
27
- [key, value]
28
- end.to_h
29
- end
30
-
31
- def extract_variables(values=@values, variables=[])
32
- values&.each do |key, value|
33
- if value.is_a?(Set)
34
- variables.concat extract_variables(value.values)
35
- elsif value.is_a?(Array)
36
- elsif value.symbol?
37
- variables << value
38
- elsif value.formal?
39
- variables << value
40
- end
41
- end
42
- variables
43
- end
44
-
45
- def to_h(raw = false)
46
- return {} unless values && !values.empty?
47
- values.inject({}) do |memo, (k, v)|
48
- if v.is_a?(Array)
49
- memo[k.to_s.to_camel_case] = v.map { |value| value.to_s(raw) }
50
- elsif v.is_a?(Set)
51
- memo[k.to_s.to_camel_case] = v.to_h
52
- else
53
- memo[k.to_s.to_camel_case] = v.to_s(raw)
54
- end
55
- memo
56
- end
57
- end
58
-
59
- def to_s(inner = false)
60
- return "" unless values && !values.empty?
61
- arr = stringify_arguments
62
- return arr.join(", ") if inner
63
- "(#{arr.join(", ")})"
64
- end
65
-
66
- private
67
-
68
- def stringify_arguments
69
- values.map do |k,v|
70
- if v.is_a?(Array)
71
- "#{k.to_s.to_camel_case}: [#{v.map(&:to_s).join(", ")}]"
72
- elsif v.is_a?(Set)
73
- "#{k.to_s.to_camel_case}: { #{v.to_s(true)} }"
74
- else
75
- "#{k.to_s.to_camel_case}: #{v.to_s}"
76
- end
77
- end
78
- end
79
-
80
- def expand_arguments(data)
81
- data.transform_values do |value|
82
- case value
83
- when Array
84
- value.map { |item| Value.from(item) }
85
- when Hash
86
- Set.new(value)
87
- else
88
- Value.from(value)
89
- end
90
- end
91
- end
92
- end
93
- end
94
- end