graphlyte 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee4eed2122126ce2d651f0f63210598a48a9fb6a6919a4a20066e932fccdab3
4
- data.tar.gz: 7d74b8dc7a8c46e949a5ea035970f3595ff02020dbc55ad819b31e5bfcd2b3e0
3
+ metadata.gz: 82edd3a321164acd153524e98420c75175deb60d1fd56d28f72f52917e35dac4
4
+ data.tar.gz: '049a43943a6ba45edff3a73347c903be52f0d4e4d7e9f76a9be50e0e45ed11a6'
5
5
  SHA512:
6
- metadata.gz: bf5f9ee7465d4120a7c343954fd912c07a14e90b23ecee94dca4c9ba077be0d2c3d2853540c74b243f715f4e30cd00e90587e189abac66e043e5a30baab7ea07
7
- data.tar.gz: f31753943431a52b0296de465a6d7f2901657a2c4be1c69fc0c91f424011bfbb12f5ad5baa090e236ddf3466b70463cf5098a3ecb72e712af8290e3ea13a85e9
6
+ metadata.gz: a1a81b6258e70829db7010ce3c2ca3cdd818dadd0cdc21878c6e10eaefd7baa54d816fd3810c92f330699d905ed5ad00f7865c169f0290e96f4290dbf5cf8160
7
+ data.tar.gz: b3bc5db253642508d0f9e93c7882525706fe7c9e1ec687e4b7f506a6096a9ba8ecb2a6e6cc1653318467911b70c01243a4bf9f55d7cd22ccf2618cfff912bfbd
data/lib/graphlyte.rb CHANGED
@@ -1,174 +1,26 @@
1
1
  require 'json'
2
+ require_relative "./graphlyte/fieldset"
3
+ require_relative "./graphlyte/query"
4
+ require_relative "./graphlyte/fragment"
5
+
2
6
  module Graphlyte
3
7
  def self.query(name = nil, &block)
4
- query = Query.new(name)
5
- block.call(query) if block
6
- query
8
+ Query.new(name, builder: build(&block))
7
9
  end
8
10
 
9
- def self.fragment(fragment_name, model_name=nil, &block)
10
- fragment = Fragment.new(fragment_name, model_name)
11
- block.call(fragment) if block
12
- fragment
11
+ def self.fragment(fragment_name, model_name, &block)
12
+ Fragment.new(fragment_name, model_name, builder: build(&block))
13
13
  end
14
14
 
15
15
  def self.fieldset(model_name=nil, &block)
16
- fieldset = Fieldset.new(model_name)
17
- block.call(fieldset) if block
18
- fieldset
19
- end
20
-
21
- module Buildable
22
- def <<(buildable)
23
- raise "Must pass a Fieldset or Fragment" unless [Fragment, Fieldset].include?(buildable.class)
24
- @fields.concat(buildable._fields) if buildable.class.eql? Fieldset
25
- @fields << buildable if buildable.class.eql? Fragment
26
- end
27
-
28
- def method_missing(method, optional_fieldset_or_args=nil, hargs={}, &block)
29
- field = [Fieldset, Fragment].include?(optional_fieldset_or_args.class) ?
30
- Field.new(method, optional_fieldset_or_args, hargs) :
31
- Field.new(method, Fieldset.empty, optional_fieldset_or_args)
32
- block.call(field.value) if block
33
- @fields << field
34
- field
35
- end
16
+ Fieldset.new(model_name, builder: build(&block))
36
17
  end
37
18
 
38
- class Fieldset
39
- include Buildable
40
-
41
- def self.empty
42
- new
43
- end
44
-
45
- def initialize(model_name = nil)
46
- @model_name = model_name
47
- @fields = []
48
- end
49
-
50
- def _model_name
51
- @model_name
52
- end
53
-
54
- def _fields
55
- @fields
56
- end
57
-
58
- def empty?
59
- @fields.empty?
60
- end
61
-
62
- def can_validate?
63
- !@model_name.nil?
64
- end
65
-
66
- def to_s(indent=0)
67
- @fields.map { |field| field.to_s(indent)}.join("\n")
68
- end
69
- end
70
-
71
- class Query < Fieldset
72
-
73
- def initialize(query_name=nil)
74
- @query_name = query_name
75
- @fields = []
76
- end
77
-
78
- def to_json
79
- { query: to_s }.to_json
80
- end
81
-
82
- def to_s(indent=0)
83
- "{\n#{super(indent + 1)}\n}\n#{format_fragments}\n"
84
- end
85
-
86
- def format_fragments
87
- str = ""
88
- flatten(@fields).each do |_, fragment|
89
- str += "\nfragment #{fragment.name}"
90
- str += " on #{fragment._model_name}" unless fragment._model_name.nil?
91
- str += " {\n#{fragment._fields.map {|f| f.to_s(1) }.join("\n")}\n}"
92
- end
93
- str
94
- end
95
-
96
- def flatten(fields=@fields, new_fields = {})
97
- fields.each do |field|
98
- if field.class.eql?(Fragment)
99
- new_fields[field.name] = field
100
- unless field._fields.empty?
101
- flatten(field._fields, new_fields)
102
- end
103
- else
104
- if field.value.class.eql?(Fragment)
105
- new_fields[field.value.name] = field.value
106
- flatten(field.value._fields, new_fields) unless field.value._fields.empty?
107
- else
108
- flatten(field.value._fields, new_fields) unless field.value._fields.empty?
109
- end
110
- end
111
- end
112
- new_fields
113
- end
114
- end
115
-
116
- class Fragment < Fieldset
117
- attr_reader :fragment_name, :name
118
-
119
- def initialize(fragment_name, model_name=nil)
120
- @fragment_name = fragment_name
121
- @name = fragment_name
122
- super(model_name)
123
- end
124
-
125
- def to_s(indent=0)
126
- actual_indent = ("\s" * indent) * 2
127
- "#{actual_indent}...#{@fragment_name}#{actual_indent}"
128
- end
129
- end
130
-
131
- class FieldArguments
132
- def initialize(data)
133
- @data = data
134
- end
135
-
136
- def to_s
137
- return @data && !@data.empty? ? "(#{@data.map{|k, v| "#{k}: \"#{v}\""}.join(", ")})" : ""
138
- end
139
- end
140
-
141
- class Field
142
- attr_reader :name, :value, :inputs, :alias
143
-
144
- def initialize(name, value=nil, hargs)
145
- @name = name
146
- @value = value
147
- @inputs = FieldArguments.new(hargs)
148
- @alias = nil
149
- end
150
-
151
- def atomic?
152
- value.empty?
153
- end
154
-
155
- def alias(name, &block)
156
- @alias = name
157
- block.call(value) if block
158
- end
19
+ private
159
20
 
160
- def to_s(indent=0)
161
- str = ""
162
- actual_indent = ("\s" * indent) * 2
163
- if @alias
164
- str += "#{actual_indent}#{@alias}: #{name}"
165
- str += inputs.to_s.empty? ? "()" : inputs.to_s
166
- str += " "
167
- else
168
- str += "#{actual_indent}#{name}#{inputs.to_s}"
169
- end
170
- str += "{\n#{value.to_s(indent + 1)}#{actual_indent}\n#{actual_indent}}" unless atomic?
171
- str
172
- end
21
+ def self.build(&block)
22
+ builder = Builder.new
23
+ block.call(builder) if block
24
+ builder
173
25
  end
174
26
  end
@@ -0,0 +1,46 @@
1
+ require_relative "./value"
2
+ module Graphlyte
3
+ module Arguments
4
+ class Set
5
+
6
+ attr_reader :values
7
+
8
+ def initialize(data)
9
+ raise ArgumentError, "input #{data} must be a hash" unless data.nil? || data.is_a?(Hash)
10
+ @values = expand_arguments(data) unless data.nil?
11
+ end
12
+
13
+ def to_s(inner = false)
14
+ return "" unless values && !values.empty?
15
+ arr = values.map do |k,v|
16
+ if v.is_a?(Array)
17
+ "#{k}: [#{v.map(&:to_s).join(", ")}]"
18
+ elsif v.is_a?(Set)
19
+ "#{k}: { #{v.to_s(true)} }"
20
+ else
21
+ "#{k}: #{v.to_s}"
22
+ end
23
+ end
24
+ return arr.join(", ") if inner
25
+ "(#{arr.join(", ")})"
26
+ end
27
+
28
+ private
29
+
30
+ def expand_arguments(data)
31
+ data.inject({}) do |memo, (k, v)|
32
+ if v.is_a?(Array)
33
+ memo[k] = v.map do |item|
34
+ Value.new(item)
35
+ end
36
+ elsif v.is_a?(Hash)
37
+ memo[k] = Set.new(v)
38
+ else
39
+ memo[k] = Value.new(v)
40
+ end
41
+ memo
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,19 @@
1
+ module Graphlyte
2
+ module Arguments
3
+ class Value
4
+ attr_reader :value
5
+
6
+ def initialize(value)
7
+ raise ArgumentError, "Hash not allowed in this context" if value.is_a? Hash
8
+ @value = value
9
+ end
10
+
11
+ def to_s
12
+ return value if value.is_a? Numeric
13
+ return "\"#{value}\"" if value.is_a? String
14
+ return "null" if value.nil?
15
+ value.to_s
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ require_relative "./field"
2
+ require_relative "./fieldset"
3
+
4
+ module Graphlyte
5
+ class Builder
6
+ def initialize
7
+ @fields = []
8
+ end
9
+
10
+ def <<(buildable)
11
+ raise "Must pass a Fieldset or Fragment" unless [Fragment, Fieldset].include?(buildable.class)
12
+
13
+ @fields.concat(buildable.fields) if buildable.class.eql? Fieldset
14
+
15
+ # todo: handle fragments better, it's not a field
16
+ @fields << buildable if buildable.class.eql? Fragment
17
+ end
18
+
19
+ def method_missing(method, fieldset_or_hargs=nil, hargs={}, &block)
20
+ # todo: camel case method
21
+
22
+ # hack for ruby bug in lower versions
23
+ if [Fieldset, Fragment].include?(fieldset_or_hargs.class)
24
+ field = Field.new(method, fieldset_or_hargs, hargs)
25
+ else
26
+ field = Field.new(method, Fieldset.empty, fieldset_or_hargs)
27
+ end
28
+
29
+ block.call(field.fieldset.builder) if block
30
+ @fields << field
31
+ field
32
+ end
33
+
34
+ # for internal use only
35
+ def >>
36
+ @fields
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,47 @@
1
+ require_relative "./arguments/set"
2
+
3
+ module Graphlyte
4
+ class Field
5
+ attr_reader :name, :fieldset, :inputs, :alias
6
+
7
+ def initialize(name, fieldset, hargs, inputs: Arguments::Set.new(hargs))
8
+ @name = to_camel_case(name.to_s)
9
+ @fieldset = fieldset
10
+ @inputs = inputs
11
+ @alias = nil
12
+ end
13
+
14
+ def atomic?
15
+ fieldset.empty?
16
+ end
17
+
18
+ def alias(name, &block)
19
+ @alias = name
20
+ block.call(fieldset.builder) if block
21
+ end
22
+
23
+ def to_s(indent=0)
24
+ str = ""
25
+ actual_indent = ("\s" * indent) * 2
26
+ if @alias
27
+ str += "#{actual_indent}#{@alias}: #{name}"
28
+ str += inputs.to_s.empty? ? "()" : inputs.to_s
29
+ else
30
+ str += "#{actual_indent}#{name}#{inputs.to_s}"
31
+ end
32
+ str += " {\n#{fieldset.to_s(indent + 1)}\n#{actual_indent}}" unless atomic?
33
+ str
34
+ end
35
+
36
+ def to_camel_case(string)
37
+ start_of_string = string.match(/(^_+)/)&.[](0)
38
+ end_of_string = string.match(/(_+$)/)&.[](0)
39
+
40
+ middle = string.split("_").reject(&:empty?).inject([]) do |memo, str|
41
+ memo << (memo.empty? ? str : str.capitalize)
42
+ end.join("")
43
+
44
+ "#{start_of_string}#{middle}#{end_of_string}"
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,36 @@
1
+ require_relative "./builder"
2
+
3
+ module Graphlyte
4
+ class Fieldset
5
+ def self.empty
6
+ new
7
+ end
8
+
9
+ attr_reader :model_name, :builder
10
+
11
+ def initialize(model_name = nil, builder: Builder.new)
12
+ @model_name = model_name
13
+ @builder = builder
14
+ end
15
+
16
+ def fields
17
+ builder.>>
18
+ end
19
+
20
+ def empty?
21
+ fields.empty?
22
+ end
23
+
24
+ def to_s(indent=0)
25
+ fields.map { |field| field.to_s(indent) }.join("\n")
26
+ end
27
+
28
+ def to_a
29
+ [ to_s ]
30
+ end
31
+
32
+ def +(fieldset)
33
+ to_s + "\n" + fieldset.to_s
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "./fieldset"
2
+
3
+ module Graphlyte
4
+ class Fragment < Fieldset
5
+ attr_reader :fragment
6
+
7
+ def initialize(fragment_name, model_name=nil, **hargs)
8
+ @fragment = fragment_name
9
+ super(model_name, **hargs)
10
+ end
11
+
12
+ def to_s(indent=0)
13
+ actual_indent = ("\s" * indent) * 2
14
+ "#{actual_indent}...#{fragment}#{actual_indent}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ module Graphlyte
2
+ class Query < Fieldset
3
+
4
+ attr_reader :name
5
+
6
+ def initialize(query_name=nil, **hargs)
7
+ @name = query_name
8
+ super(**hargs)
9
+ end
10
+
11
+ def to_json
12
+ { query: to_s }.to_json
13
+ end
14
+
15
+ def to_s(indent=0)
16
+ "{\n#{super(indent + 1)}\n}#{format_fragments}"
17
+ end
18
+
19
+ def format_fragments
20
+ str = "\n"
21
+ flatten(builder.>>).each do |_, fragment|
22
+ str += "\nfragment #{fragment.fragment}"
23
+ str += " on #{fragment.model_name}" unless fragment.model_name.nil?
24
+ str += " {\n#{fragment.fields.map {|f| f.to_s(1) }.join("\n")}\n}"
25
+ end
26
+ str
27
+ end
28
+
29
+ def flatten(fields, new_fields = {})
30
+ fields.each do |field|
31
+ if field.class.eql?(Fragment)
32
+ new_fields[field.fragment] = field
33
+ unless field.empty?
34
+ flatten(field.fields, new_fields)
35
+ end
36
+ else
37
+ if field.fieldset.class.eql?(Fragment)
38
+ new_fields[field.fieldset.fragment] = field.fieldset
39
+ flatten(field.fieldset.fields, new_fields) unless field.atomic?
40
+ else
41
+ flatten(field.fieldset.fields, new_fields) unless field.atomic?
42
+ end
43
+ end
44
+ end
45
+ new_fields
46
+ end
47
+ end
48
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphlyte
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Gregory
@@ -45,6 +45,13 @@ extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
47
  - lib/graphlyte.rb
48
+ - lib/graphlyte/arguments/set.rb
49
+ - lib/graphlyte/arguments/value.rb
50
+ - lib/graphlyte/builder.rb
51
+ - lib/graphlyte/field.rb
52
+ - lib/graphlyte/fieldset.rb
53
+ - lib/graphlyte/fragment.rb
54
+ - lib/graphlyte/query.rb
48
55
  homepage: https://rubygems.org/gems/graphlyte
49
56
  licenses:
50
57
  - MIT