tinygql 0.1.2 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/bin/bench.rb CHANGED
@@ -1,11 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $:.unshift(File.expand_path("../lib", __dir__))
4
3
  require "tinygql"
5
- require "benchmark"
4
+ require "benchmark/ips"
6
5
 
7
6
  source = File.read(File.expand_path("../test/kitchen-sink.graphql", __dir__))
8
7
 
9
- Benchmark.bm do |x|
10
- x.report { 10_000.times { TinyGQL::Parser.new(source).parse } }
8
+ files = Dir[File.join(File.expand_path("../benchmark", __dir__), "**/*")].select { |f| File.file? f }
9
+
10
+ Benchmark.ips do |x|
11
+ x.report "kitchen-sink" do
12
+ TinyGQL.parse source
13
+ end
14
+
15
+ files.each do |file_name|
16
+ data = File.read file_name
17
+ name = File.basename(file_name, File.extname(file_name))
18
+ x.report name do
19
+ TinyGQL.parse data
20
+ end
21
+ end
11
22
  end
data/bin/profile.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "vernier"
2
+
3
+ Vernier.trace(out: "time_profile.json") {
4
+ require_relative "bench"
5
+ }
data/lib/tinygql/nodes.rb CHANGED
@@ -42,6 +42,11 @@ module TinyGQL
42
42
  def executable_directive_location?; false; end
43
43
  def type_system_directive_location?; false; end
44
44
  def directive_definition?; false; end
45
+ def scalar_type_extension?; false; end
46
+ def interface_type_extension?; false; end
47
+ def union_type_extension?; false; end
48
+ def enum_type_extension?; false; end
49
+ def input_object_type_extension?; false; end
45
50
  def each(&blk)
46
51
  yield self
47
52
  children.each { |v| v.each(&blk) }
@@ -422,7 +427,7 @@ module TinyGQL
422
427
  def directive?; true; end
423
428
 
424
429
  def children
425
- ary = []; ary.concat(arguments); ary
430
+ ary = []; ary.concat(arguments) if arguments; ary
426
431
  end
427
432
  end
428
433
  class TypeCondition < Node
@@ -488,7 +493,7 @@ module TinyGQL
488
493
  def fragment_spread?; true; end
489
494
 
490
495
  def children
491
- ary = []; ary << fragment_name; ary.concat(directives) if directives; ary
496
+ ary = []; ary.concat(directives) if directives; ary
492
497
  end
493
498
  end
494
499
  class FragmentDefinition < Node
@@ -512,7 +517,7 @@ module TinyGQL
512
517
  def fragment_definition?; true; end
513
518
 
514
519
  def children
515
- ary = []; ary << fragment_name; ary << type_condition; ary.concat(directives) if directives; ary.concat(selection_set); ary
520
+ ary = []; ary << type_condition; ary.concat(directives) if directives; ary.concat(selection_set); ary
516
521
  end
517
522
  end
518
523
  class RootOperationTypeDefinition < Node
@@ -534,13 +539,14 @@ module TinyGQL
534
539
  def root_operation_type_definition?; true; end
535
540
 
536
541
  def children
537
- ary = []; ary << operation_type; ary << named_type; ary
542
+ ary = []; ary << named_type; ary
538
543
  end
539
544
  end
540
545
  class SchemaDefinition < Node
541
- attr_reader :directives, :root_operation_definitions
546
+ attr_reader :description, :directives, :root_operation_definitions
542
547
 
543
- def initialize directives, root_operation_definitions
548
+ def initialize description, directives, root_operation_definitions
549
+ @description = description
544
550
  @directives = directives
545
551
  @root_operation_definitions = root_operation_definitions
546
552
  end
@@ -556,7 +562,7 @@ module TinyGQL
556
562
  def schema_definition?; true; end
557
563
 
558
564
  def children
559
- ary = []; ary.concat(directives) if directives; ary.concat(root_operation_definitions); ary
565
+ ary = []; ary << description if description; ary.concat(directives) if directives; ary.concat(root_operation_definitions); ary
560
566
  end
561
567
  end
562
568
  class FieldDefinition < Node
@@ -581,7 +587,7 @@ module TinyGQL
581
587
  def field_definition?; true; end
582
588
 
583
589
  def children
584
- ary = []; ary.concat(arguments_definition) if arguments_definition; ary << type; ary.concat(directives) if directives; ary
590
+ ary = []; ary << description if description; ary.concat(arguments_definition) if arguments_definition; ary << type; ary.concat(directives) if directives; ary
585
591
  end
586
592
  end
587
593
  class InputValueDefinition < Node
@@ -606,7 +612,7 @@ module TinyGQL
606
612
  def input_value_definition?; true; end
607
613
 
608
614
  def children
609
- ary = []; ary << type; ary << default_value if default_value; ary.concat(directives) if directives; ary
615
+ ary = []; ary << description if description; ary << type; ary << default_value if default_value; ary.concat(directives) if directives; ary
610
616
  end
611
617
  end
612
618
  class ObjectTypeDefinition < Node
@@ -631,7 +637,7 @@ module TinyGQL
631
637
  def object_type_definition?; true; end
632
638
 
633
639
  def children
634
- ary = []; ary.concat(implements_interfaces) if implements_interfaces; ary.concat(directives) if directives; ary.concat(fields_definition) if fields_definition; ary
640
+ ary = []; ary << description if description; ary.concat(implements_interfaces) if implements_interfaces; ary.concat(directives) if directives; ary.concat(fields_definition) if fields_definition; ary
635
641
  end
636
642
  end
637
643
  class InterfaceTypeDefinition < Node
@@ -655,7 +661,7 @@ module TinyGQL
655
661
  def interface_type_definition?; true; end
656
662
 
657
663
  def children
658
- ary = []; ary.concat(directives) if directives; ary.concat(fields_definition) if fields_definition; ary
664
+ ary = []; ary << description if description; ary.concat(directives) if directives; ary.concat(fields_definition) if fields_definition; ary
659
665
  end
660
666
  end
661
667
  class UnionTypeDefinition < Node
@@ -679,7 +685,7 @@ module TinyGQL
679
685
  def union_type_definition?; true; end
680
686
 
681
687
  def children
682
- ary = []; ary.concat(directives) if directives; ary.concat(union_member_types) if union_member_types; ary
688
+ ary = []; ary << description if description; ary.concat(directives) if directives; ary.concat(union_member_types) if union_member_types; ary
683
689
  end
684
690
  end
685
691
  class ScalarTypeDefinition < Node
@@ -702,7 +708,7 @@ module TinyGQL
702
708
  def scalar_type_definition?; true; end
703
709
 
704
710
  def children
705
- ary = []; ary.concat(directives) if directives; ary
711
+ ary = []; ary << description if description; ary.concat(directives) if directives; ary
706
712
  end
707
713
  end
708
714
  class EnumValueDefinition < Node
@@ -725,7 +731,7 @@ module TinyGQL
725
731
  def enum_value_definition?; true; end
726
732
 
727
733
  def children
728
- ary = []; ary << enum_value; ary.concat(directives) if directives; ary
734
+ ary = []; ary << description if description; ary << enum_value; ary.concat(directives) if directives; ary
729
735
  end
730
736
  end
731
737
  class EnumTypeDefinition < Node
@@ -749,7 +755,7 @@ module TinyGQL
749
755
  def enum_type_definition?; true; end
750
756
 
751
757
  def children
752
- ary = []; ary.concat(directives) if directives; ary.concat(enum_value_definition) if enum_value_definition; ary
758
+ ary = []; ary << description if description; ary.concat(directives) if directives; ary.concat(enum_value_definition) if enum_value_definition; ary
753
759
  end
754
760
  end
755
761
  class InputObjectTypeDefinition < Node
@@ -773,7 +779,7 @@ module TinyGQL
773
779
  def input_object_type_definition?; true; end
774
780
 
775
781
  def children
776
- ary = []; ary.concat(directives) if directives; ary.concat(input_fields_definition) if input_fields_definition; ary
782
+ ary = []; ary << description if description; ary.concat(directives) if directives; ary.concat(input_fields_definition) if input_fields_definition; ary
777
783
  end
778
784
  end
779
785
  class ObjectTypeExtension < Node
@@ -863,7 +869,122 @@ module TinyGQL
863
869
  def directive_definition?; true; end
864
870
 
865
871
  def children
866
- ary = []; ary.concat(arguments_definition) if arguments_definition; ary.concat(directive_locations); ary
872
+ ary = []; ary << description if description; ary.concat(arguments_definition) if arguments_definition; ary.concat(directive_locations); ary
873
+ end
874
+ end
875
+ class ScalarTypeExtension < Node
876
+ attr_reader :name, :directives
877
+
878
+ def initialize name, directives
879
+ @name = name
880
+ @directives = directives
881
+ end
882
+
883
+ def accept viz
884
+ viz.handle_scalar_type_extension self
885
+ end
886
+
887
+ def fold viz, seed
888
+ viz.handle_scalar_type_extension self, seed
889
+ end
890
+
891
+ def scalar_type_extension?; true; end
892
+
893
+ def children
894
+ ary = []; ary.concat(directives) if directives; ary
895
+ end
896
+ end
897
+ class InterfaceTypeExtension < Node
898
+ attr_reader :name, :implements_interfaces, :directives, :fields_definition
899
+
900
+ def initialize name, implements_interfaces, directives, fields_definition
901
+ @name = name
902
+ @implements_interfaces = implements_interfaces
903
+ @directives = directives
904
+ @fields_definition = fields_definition
905
+ end
906
+
907
+ def accept viz
908
+ viz.handle_interface_type_extension self
909
+ end
910
+
911
+ def fold viz, seed
912
+ viz.handle_interface_type_extension self, seed
913
+ end
914
+
915
+ def interface_type_extension?; true; end
916
+
917
+ def children
918
+ ary = []; ary.concat(implements_interfaces) if implements_interfaces; ary.concat(directives) if directives; ary.concat(fields_definition) if fields_definition; ary
919
+ end
920
+ end
921
+ class UnionTypeExtension < Node
922
+ attr_reader :name, :directives, :union_member_types
923
+
924
+ def initialize name, directives, union_member_types
925
+ @name = name
926
+ @directives = directives
927
+ @union_member_types = union_member_types
928
+ end
929
+
930
+ def accept viz
931
+ viz.handle_union_type_extension self
932
+ end
933
+
934
+ def fold viz, seed
935
+ viz.handle_union_type_extension self, seed
936
+ end
937
+
938
+ def union_type_extension?; true; end
939
+
940
+ def children
941
+ ary = []; ary.concat(directives) if directives; ary.concat(union_member_types) if union_member_types; ary
942
+ end
943
+ end
944
+ class EnumTypeExtension < Node
945
+ attr_reader :name, :directives, :enum_value_definition
946
+
947
+ def initialize name, directives, enum_value_definition
948
+ @name = name
949
+ @directives = directives
950
+ @enum_value_definition = enum_value_definition
951
+ end
952
+
953
+ def accept viz
954
+ viz.handle_enum_type_extension self
955
+ end
956
+
957
+ def fold viz, seed
958
+ viz.handle_enum_type_extension self, seed
959
+ end
960
+
961
+ def enum_type_extension?; true; end
962
+
963
+ def children
964
+ ary = []; ary.concat(directives) if directives; ary.concat(enum_value_definition) if enum_value_definition; ary
965
+ end
966
+ end
967
+ class InputObjectTypeExtension < Node
968
+ attr_reader :name, :directives, :input_fields_definition
969
+
970
+ def initialize name, directives, input_fields_definition
971
+ @name = name
972
+ @directives = directives
973
+ @input_fields_definition = input_fields_definition
974
+ end
975
+
976
+ def accept viz
977
+ viz.handle_input_object_type_extension self
978
+ end
979
+
980
+ def fold viz, seed
981
+ viz.handle_input_object_type_extension self, seed
982
+ end
983
+
984
+ def input_object_type_extension?; true; end
985
+
986
+ def children
987
+ ary = []; ary.concat(directives) if directives; ary.concat(input_fields_definition) if input_fields_definition; ary
867
988
  end
868
989
  end
869
990
  end
@@ -84,7 +84,7 @@ nodes:
84
84
  - name: Directive
85
85
  fields:
86
86
  - name: literal
87
- - arguments: list
87
+ - arguments?: list
88
88
 
89
89
  - name: TypeCondition
90
90
  fields:
@@ -98,29 +98,30 @@ nodes:
98
98
 
99
99
  - name: FragmentSpread
100
100
  fields:
101
- - fragment_name
101
+ - fragment_name: literal
102
102
  - directives?: list
103
103
 
104
104
  - name: FragmentDefinition
105
105
  fields:
106
- - fragment_name
106
+ - fragment_name: literal
107
107
  - type_condition
108
108
  - directives?: list
109
109
  - selection_set: list
110
110
 
111
111
  - name: RootOperationTypeDefinition
112
112
  fields:
113
- - operation_type
113
+ - operation_type: literal
114
114
  - named_type
115
115
 
116
116
  - name: SchemaDefinition
117
117
  fields:
118
+ - description?
118
119
  - directives?: list
119
120
  - root_operation_definitions: list
120
121
 
121
122
  - name: FieldDefinition
122
123
  fields:
123
- - description?: literal
124
+ - description?
124
125
  - name: literal
125
126
  - arguments_definition?: list
126
127
  - type
@@ -128,7 +129,7 @@ nodes:
128
129
 
129
130
  - name: InputValueDefinition
130
131
  fields:
131
- - description?: literal
132
+ - description?
132
133
  - name: literal
133
134
  - type
134
135
  - default_value?
@@ -136,7 +137,7 @@ nodes:
136
137
 
137
138
  - name: ObjectTypeDefinition
138
139
  fields:
139
- - description?: literal
140
+ - description?
140
141
  - name: literal
141
142
  - implements_interfaces?: list
142
143
  - directives?: list
@@ -144,40 +145,40 @@ nodes:
144
145
 
145
146
  - name: InterfaceTypeDefinition
146
147
  fields:
147
- - description?: literal
148
+ - description?
148
149
  - name: literal
149
150
  - directives?: list
150
151
  - fields_definition?: list
151
152
 
152
153
  - name: UnionTypeDefinition
153
154
  fields:
154
- - description?: literal
155
+ - description?
155
156
  - name: literal
156
157
  - directives?: list
157
158
  - union_member_types?: list
158
159
 
159
160
  - name: ScalarTypeDefinition
160
161
  fields:
161
- - description?: literal
162
+ - description?
162
163
  - name: literal
163
164
  - directives?: list
164
165
 
165
166
  - name: EnumValueDefinition
166
167
  fields:
167
- - description?: literal
168
+ - description?
168
169
  - enum_value
169
170
  - directives?: list
170
171
 
171
172
  - name: EnumTypeDefinition
172
173
  fields:
173
- - description?: literal
174
+ - description?
174
175
  - name: literal
175
176
  - directives?: list
176
177
  - enum_value_definition?: list
177
178
 
178
179
  - name: InputObjectTypeDefinition
179
180
  fields:
180
- - description?: literal
181
+ - description?
181
182
  - name: literal
182
183
  - directives?: list
183
184
  - input_fields_definition?: list
@@ -199,7 +200,37 @@ nodes:
199
200
 
200
201
  - name: DirectiveDefinition
201
202
  fields:
202
- - description?: literal
203
+ - description?
203
204
  - name: literal
204
205
  - arguments_definition?: list
205
206
  - directive_locations: list
207
+
208
+ - name: ScalarTypeExtension
209
+ fields:
210
+ - name: literal
211
+ - directives?: list
212
+
213
+ - name: InterfaceTypeExtension
214
+ fields:
215
+ - name: literal
216
+ - implements_interfaces?: list
217
+ - directives?: list
218
+ - fields_definition?: list
219
+
220
+ - name: UnionTypeExtension
221
+ fields:
222
+ - name: literal
223
+ - directives?: list
224
+ - union_member_types?: list
225
+
226
+ - name: EnumTypeExtension
227
+ fields:
228
+ - name: literal
229
+ - directives?: list
230
+ - enum_value_definition?: list
231
+
232
+ - name: InputObjectTypeExtension
233
+ fields:
234
+ - name: literal
235
+ - directives?: list
236
+ - input_fields_definition?: list
@@ -7,7 +7,9 @@ module TinyGQL
7
7
  class Parser
8
8
  class UnexpectedToken < StandardError; end
9
9
 
10
- attr_reader :token_name
10
+ def self.parse doc
11
+ new(doc).parse
12
+ end
11
13
 
12
14
  def initialize doc
13
15
  @lexer = Lexer.new doc
@@ -21,6 +23,8 @@ module TinyGQL
21
23
 
22
24
  private
23
25
 
26
+ attr_reader :token_name
27
+
24
28
  def document
25
29
  Nodes::Document.new definition_list
26
30
  end
@@ -40,19 +44,66 @@ module TinyGQL
40
44
  when :EXTEND
41
45
  type_system_extension
42
46
  else
43
- type_system_definition
47
+ desc = if at?(:STRING); string_value; end
48
+
49
+ type_system_definition desc
44
50
  end
45
51
  end
46
52
 
47
53
  def type_system_extension
48
54
  expect_token :EXTEND
49
55
  case token_name
56
+ when :SCALAR then scalar_type_extension
50
57
  when :TYPE then object_type_extension
58
+ when :INTERFACE then interface_type_extension
59
+ when :UNION then union_type_extension
60
+ when :ENUM then enum_type_extension
61
+ when :INPUT then input_object_type_extension
51
62
  else
52
- expect_token :FAIL
63
+ expect_token :SCALAR
53
64
  end
54
65
  end
55
66
 
67
+ def input_object_type_extension
68
+ expect_token :INPUT
69
+ name = self.name
70
+ directives = if at?(:DIR_SIGN); self.directives; end
71
+ input_fields_definition = if at?(:LCURLY); self.input_fields_definition; end
72
+ Nodes::InputObjectTypeExtension.new(name, directives, input_fields_definition)
73
+ end
74
+
75
+ def enum_type_extension
76
+ expect_token :ENUM
77
+ name = self.name
78
+ directives = if at?(:DIR_SIGN); self.directives; end
79
+ enum_values_definition = if at?(:LCURLY); self.enum_values_definition; end
80
+ Nodes::EnumTypeExtension.new(name, directives, enum_values_definition)
81
+ end
82
+
83
+ def union_type_extension
84
+ expect_token :UNION
85
+ name = self.name
86
+ directives = if at?(:DIR_SIGN); self.directives; end
87
+ union_member_types = if at?(:EQUALS); self.union_member_types; end
88
+ Nodes::UnionTypeExtension.new(name, directives, union_member_types)
89
+ end
90
+
91
+ def interface_type_extension
92
+ expect_token :INTERFACE
93
+ name = self.name
94
+ implements_interfaces = if at?(:IMPLEMENTS); self.implements_interfaces; end
95
+ directives = if at?(:DIR_SIGN); self.directives; end
96
+ fields_definition = if at?(:LCURLY); self.fields_definition; end
97
+ Nodes::InterfaceTypeExtension.new(name, implements_interfaces, directives, fields_definition)
98
+ end
99
+
100
+ def scalar_type_extension
101
+ expect_token :SCALAR
102
+ name = self.name
103
+ directives = if at?(:DIR_SIGN); self.directives; end
104
+ Nodes::ScalarTypeExtension.new(name, directives)
105
+ end
106
+
56
107
  def object_type_extension
57
108
  expect_token :TYPE
58
109
  name = self.name
@@ -62,12 +113,12 @@ module TinyGQL
62
113
  Nodes::ObjectTypeExtension.new(name, implements_interfaces, directives, fields_definition)
63
114
  end
64
115
 
65
- def type_system_definition
116
+ def type_system_definition desc
66
117
  case token_name
67
- when :SCHEMA then schema_definition
68
- when :DIRECTIVE then directive_defintion(nil)
118
+ when :SCHEMA then schema_definition(desc)
119
+ when :DIRECTIVE then directive_defintion(desc)
69
120
  else
70
- type_definition(nil)
121
+ type_definition(desc)
71
122
  end
72
123
  end
73
124
 
@@ -91,9 +142,11 @@ module TinyGQL
91
142
  end
92
143
 
93
144
  def directive_location
94
- case token_name
145
+ directive = expect_token_value :IDENTIFIER
146
+
147
+ case directive
95
148
  when "QUERY", "MUTATION", "SUBSCRIPTION", "FIELD", "FRAGMENT_DEFINITION", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"
96
- Nodes::ExecutableDirectiveLocation.new(accept_token_value)
149
+ Nodes::ExecutableDirectiveLocation.new(directive)
97
150
  when "SCHEMA",
98
151
  "SCALAR",
99
152
  "OBJECT",
@@ -105,9 +158,9 @@ module TinyGQL
105
158
  "ENUM_VALUE",
106
159
  "INPUT_OBJECT",
107
160
  "INPUT_FIELD_DEFINITION"
108
- Nodes::TypeSystemDirectiveLocation.new(accept_token_value)
161
+ Nodes::TypeSystemDirectiveLocation.new(directive)
109
162
  else
110
- expect_token(:IDENTIFIER); nil # error
163
+ raise UnexpectedToken, "Expected directive #{directive}"
111
164
  end
112
165
  end
113
166
 
@@ -120,7 +173,7 @@ module TinyGQL
120
173
  when :ENUM then enum_type_definition(desc)
121
174
  when :INPUT then input_object_type_definition(desc)
122
175
  else
123
- expect_token :FAIL
176
+ expect_token :TYPE
124
177
  end
125
178
  end
126
179
 
@@ -161,7 +214,7 @@ module TinyGQL
161
214
  end
162
215
 
163
216
  def enum_value_definition
164
- description = if at?(:STRING); accept_token_value; end
217
+ description = if at?(:STRING); string_value; end
165
218
  enum_value = self.enum_value
166
219
  directives = if at?(:DIR_SIGN); self.directives; end
167
220
  Nodes::EnumValueDefinition.new(description, enum_value, directives)
@@ -221,7 +274,7 @@ module TinyGQL
221
274
  end
222
275
 
223
276
  def field_definition
224
- description = if at?(:STRING); accept_token_value; end
277
+ description = if at?(:STRING); string_value; end
225
278
  name = self.name
226
279
  arguments_definition = if at?(:LPAREN); self.arguments_definition; end
227
280
  expect_token :COLON
@@ -242,7 +295,7 @@ module TinyGQL
242
295
  end
243
296
 
244
297
  def input_value_definition
245
- description = if at?(:STRING); accept_token_value; end
298
+ description = if at?(:STRING); string_value; end
246
299
  name = self.name
247
300
  expect_token :COLON
248
301
  type = self.type
@@ -262,14 +315,14 @@ module TinyGQL
262
315
  list
263
316
  end
264
317
 
265
- def schema_definition
318
+ def schema_definition desc
266
319
  expect_token :SCHEMA
267
320
 
268
321
  directives = if at?(:DIR_SIGN); self.directives; end
269
322
  expect_token :LCURLY
270
323
  defs = root_operation_type_definition
271
324
  expect_token :RCURLY
272
- Nodes::SchemaDefinition.new(directives, defs)
325
+ Nodes::SchemaDefinition.new(desc, directives, defs)
273
326
  end
274
327
 
275
328
  def root_operation_type_definition
@@ -292,7 +345,7 @@ module TinyGQL
292
345
 
293
346
  def fragment_definition
294
347
  expect_token :FRAGMENT
295
- expect_token(:FAIL) if at?(:ON)
348
+ expect_token(:IDENTIFIER) if at?(:ON)
296
349
  name = self.name
297
350
  tc = self.type_condition
298
351
  directives = if at?(:DIR_SIGN)
@@ -345,15 +398,15 @@ module TinyGQL
345
398
  when :ON, :DIR_SIGN, :LCURLY then inline_fragment
346
399
  when :IDENTIFIER then fragment_spread
347
400
  else
348
- expect_token :FAIL
401
+ expect_token :IDENTIFIER
349
402
  end
350
403
  end
351
404
 
352
405
  def fragment_spread
353
406
  name = self.name
354
- directives = if at?(:DIR_SIGN)
355
- self.directives
356
- end
407
+ directives = if at?(:DIR_SIGN); self.directives; end
408
+
409
+ expect_token(:IDENTIFIER) if at?(:ON)
357
410
 
358
411
  Nodes::FragmentSpread.new(name, directives)
359
412
  end
@@ -469,7 +522,7 @@ module TinyGQL
469
522
  when :LCURLY then object_value
470
523
  when :VAR_SIGN then variable
471
524
  else
472
- expect_token :FAIL
525
+ expect_token :INT
473
526
  end
474
527
  end
475
528
 
@@ -1,3 +1,3 @@
1
1
  module TinyGQL
2
- VERSION = '0.1.2'
2
+ VERSION = '0.1.4'
3
3
  end