mongoid_query_string_interface 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -12,4 +12,5 @@ end
12
12
 
13
13
  platforms :mri_19 do
14
14
  gem "ruby-debug19", :require => 'ruby-debug' if RUBY_VERSION < "1.9.3"
15
+ gem 'simplecov', :require => false
15
16
  end
data/Gemfile.lock CHANGED
@@ -1,46 +1,46 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mongoid_query_string_interface (0.2.4)
4
+ mongoid_query_string_interface (0.3.0)
5
5
  json (>= 1.4.6)
6
6
  mongoid (~> 2.0.0.rc)
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
- activemodel (3.0.3)
12
- activesupport (= 3.0.3)
11
+ activemodel (3.0.5)
12
+ activesupport (= 3.0.5)
13
13
  builder (~> 2.1.2)
14
14
  i18n (~> 0.4)
15
- activesupport (3.0.3)
15
+ activesupport (3.0.5)
16
16
  archive-tar-minitar (0.5.2)
17
- bson (1.2.0)
18
- bson_ext (1.2.0)
17
+ bson (1.2.4)
18
+ bson_ext (1.2.4)
19
19
  builder (2.1.2)
20
20
  columnize (0.3.2)
21
- database_cleaner (0.6.1)
21
+ database_cleaner (0.6.6)
22
22
  diff-lcs (1.1.2)
23
23
  i18n (0.5.0)
24
- json (1.4.6)
24
+ json (1.5.1)
25
25
  linecache (0.43)
26
26
  linecache19 (0.5.11)
27
27
  ruby_core_source (>= 0.1.4)
28
- mongo (1.2.0)
29
- bson (>= 1.2.0)
30
- mongoid (2.0.0.rc.7)
28
+ mongo (1.2.4)
29
+ bson (>= 1.2.4)
30
+ mongoid (2.0.0.rc.8)
31
31
  activemodel (~> 3.0)
32
32
  mongo (~> 1.2)
33
33
  tzinfo (~> 0.3.22)
34
34
  will_paginate (~> 3.0.pre)
35
35
  rake (0.8.7)
36
- rspec (2.4.0)
37
- rspec-core (~> 2.4.0)
38
- rspec-expectations (~> 2.4.0)
39
- rspec-mocks (~> 2.4.0)
40
- rspec-core (2.4.0)
41
- rspec-expectations (2.4.0)
36
+ rspec (2.5.0)
37
+ rspec-core (~> 2.5.0)
38
+ rspec-expectations (~> 2.5.0)
39
+ rspec-mocks (~> 2.5.0)
40
+ rspec-core (2.5.1)
41
+ rspec-expectations (2.5.0)
42
42
  diff-lcs (~> 1.1.2)
43
- rspec-mocks (2.4.0)
43
+ rspec-mocks (2.5.0)
44
44
  ruby-debug (0.10.4)
45
45
  columnize (>= 0.1)
46
46
  ruby-debug-base (~> 0.10.4.0)
@@ -56,7 +56,10 @@ GEM
56
56
  ruby-debug-base19 (>= 0.11.19)
57
57
  ruby_core_source (0.1.4)
58
58
  archive-tar-minitar (>= 0.5.2)
59
- tzinfo (0.3.24)
59
+ simplecov (0.4.1)
60
+ simplecov-html (~> 0.4.3)
61
+ simplecov-html (0.4.3)
62
+ tzinfo (0.3.25)
60
63
  will_paginate (3.0.pre2)
61
64
 
62
65
  PLATFORMS
@@ -73,3 +76,4 @@ DEPENDENCIES
73
76
  rspec (>= 2.3.0)
74
77
  ruby-debug
75
78
  ruby-debug19
79
+ simplecov
@@ -3,10 +3,9 @@ module Mongoid
3
3
  module Parsers
4
4
  class ArrayParser
5
5
  ARRAY_SEPARATOR = '|'
6
- ARRAY_CONDITIONAL_OPERATORS = [:$all, :$in, :$nin]
7
6
 
8
7
  def parseable?(value, operator)
9
- operator && ARRAY_CONDITIONAL_OPERATORS.include?(operator.to_sym)
8
+ operator && conditional_operators.include?(operator)
10
9
  end
11
10
 
12
11
  def parse(value)
@@ -19,6 +18,10 @@ module Mongoid
19
18
  def regex_parser
20
19
  @regex_parser ||= RegexParser.new
21
20
  end
21
+
22
+ def conditional_operators
23
+ @conditional_operators ||= Mongoid::QueryStringInterface::ARRAY_CONDITIONAL_OPERATORS.map { |o| "$#{o}" }
24
+ end
22
25
  end
23
26
  end
24
27
  end
@@ -2,14 +2,14 @@ module Mongoid
2
2
  module QueryStringInterface
3
3
  module Parsers
4
4
  class DateTimeParser
5
+ DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?([ \t]*)(Z?|[-+]\d{2}?(:?\d{2})?))$/
6
+
5
7
  def parseable?(value, operator)
6
- not parse(value).nil?
8
+ DATE_REGEX.match(value)
7
9
  end
8
10
 
9
11
  def parse(value)
10
- value.to_time and Time.parse(value)
11
- rescue Exception
12
- nil
12
+ Time.parse(value)
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,149 @@
1
+ require 'cgi'
2
+
3
+ require File.expand_path(File.join('date_time_parser'), File.dirname(__FILE__))
4
+ require File.expand_path(File.join('number_parser'), File.dirname(__FILE__))
5
+ require File.expand_path(File.join('array_parser'), File.dirname(__FILE__))
6
+ require File.expand_path(File.join('regex_parser'), File.dirname(__FILE__))
7
+ require File.expand_path(File.join('boolean_and_nil_parser'), File.dirname(__FILE__))
8
+
9
+ module Mongoid
10
+ module QueryStringInterface
11
+ module Parsers
12
+ class FilterParser
13
+ attr_reader :raw_attribute, :raw_value
14
+
15
+ PARSERS = [
16
+ Mongoid::QueryStringInterface::Parsers::DateTimeParser.new,
17
+ Mongoid::QueryStringInterface::Parsers::NumberParser.new,
18
+ Mongoid::QueryStringInterface::Parsers::ArrayParser.new,
19
+ Mongoid::QueryStringInterface::Parsers::RegexParser.new,
20
+ Mongoid::QueryStringInterface::Parsers::BooleanAndNilParser.new
21
+ ]
22
+
23
+ def initialize(raw_attribute, raw_value)
24
+ @raw_attribute = raw_attribute
25
+ @raw_value = raw_value
26
+ end
27
+
28
+ def attribute
29
+ @attribute ||= parsed_attribute
30
+ end
31
+
32
+ def value
33
+ @value ||= expanded_value
34
+ end
35
+
36
+ def operator
37
+ @operator ||= operator_from(raw_attribute)
38
+ end
39
+
40
+ def or_attribute?
41
+ raw_attribute == 'or'
42
+ end
43
+
44
+ def include?(other_filter)
45
+ if or_attribute?
46
+ json_value.any? do |filters|
47
+ filters.filter_parsers.any? do |filter_parser|
48
+ filter_parser.attribute == other_filter.attribute &&
49
+ conditional_array_operators.include?(filter_parser.operator) &&
50
+ filter_parser.operator == other_filter.operator
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def merge(other_filter)
57
+ if or_attribute?
58
+ @value = json_value.map do |filters|
59
+ filters.filter_parsers << other_filter
60
+ filters.parse
61
+ end
62
+ elsif conditional_array_operators.include?(other_filter.operator) && operator == other_filter.operator
63
+ @value = value.inject({}) do |result, filter|
64
+ filter_operation, filter_value = filter
65
+ filter_value = filter_value.concat(other_filter.value[filter_operation]) if other_filter.value[filter_operation]
66
+ result[filter_operation] = filter_value
67
+ result
68
+ end
69
+ else
70
+ @value = value.merge(other_filter.value)
71
+ end
72
+ end
73
+
74
+ private
75
+ def parsed_attribute
76
+ if or_attribute?
77
+ '$or'
78
+ elsif raw_attribute =~ Mongoid::QueryStringInterface::ATTRIBUTE_REGEX
79
+ $1
80
+ else
81
+ raw_attribute
82
+ end
83
+ end
84
+
85
+ def expanded_value
86
+ if operator
87
+ if or_attribute?
88
+ parsed_json_value
89
+ else
90
+ { operator => parsed_value }
91
+ end
92
+ else
93
+ parsed_value
94
+ end
95
+ end
96
+
97
+ def parsed_value
98
+ if raw_value.is_a?(String)
99
+ PARSERS.each do |parser|
100
+ return parser.parse(unescaped_raw_value) if parser.parseable?(unescaped_raw_value, operator)
101
+ end
102
+
103
+ return nil
104
+ else
105
+ raw_value
106
+ end
107
+ end
108
+
109
+ def parsed_json_value
110
+ if unescaped_raw_value.is_a?(String)
111
+ json_value.map(&:parse)
112
+ else
113
+ unescaped_raw_value
114
+ end
115
+ end
116
+
117
+ def json_value
118
+ raw_or_data = ::JSON.parse(unescaped_raw_value)
119
+
120
+ raise "$or query filters must be given as an array of hashes" unless valid_or_filters?(raw_or_data)
121
+
122
+ raw_or_data.map do |filters|
123
+ FiltersParser.new(filters)
124
+ end
125
+ end
126
+
127
+ def valid_or_filters?(raw_or_data)
128
+ raw_or_data.is_a?(Array) and raw_or_data.all? { |item| item.is_a?(Hash) }
129
+ end
130
+
131
+ def unescaped_raw_value
132
+ @unescaped_raw_value ||= raw_value.is_a?(String) ? CGI.unescape(raw_value) : raw_value
133
+ end
134
+
135
+ def conditional_array_operators
136
+ Mongoid::QueryStringInterface::ARRAY_CONDITIONAL_OPERATORS.map { |o| "$#{o}" }
137
+ end
138
+
139
+ def operator_from(attribute)
140
+ if or_attribute?
141
+ '$or'
142
+ elsif attribute =~ Mongoid::QueryStringInterface::OPERATOR_REGEX
143
+ "$#{$1}"
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,68 @@
1
+ module Mongoid
2
+ module QueryStringInterface
3
+ module Parsers
4
+ class FiltersParser
5
+ attr_reader :filters, :default_filters
6
+
7
+ def initialize(filters, default_filters={})
8
+ @filters = filters.with_indifferent_access
9
+ @default_filters = default_filters.with_indifferent_access
10
+ end
11
+
12
+ def parse
13
+ default_filters.merge(parsed_filters)
14
+ end
15
+
16
+ def filter_parsers
17
+ @filter_parsers ||= filters.map do |raw_attribute, raw_value|
18
+ FilterParser.new(raw_attribute, raw_value)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def parsed_filters
25
+ filter_parsers_hash.inject({}) do |result, item|
26
+ attribute, filter_parser = item
27
+
28
+ result[attribute] = filter_parser.value
29
+
30
+ result
31
+ end
32
+ end
33
+
34
+ def filter_parsers_hash
35
+ optimized_filter_parsers.inject({}) do |result, filter_parser|
36
+ if result.has_key?(filter_parser.attribute)
37
+ result[filter_parser.attribute].merge(filter_parser)
38
+ else
39
+ result[filter_parser.attribute] = filter_parser
40
+ end
41
+
42
+ result
43
+ end
44
+ end
45
+
46
+ def optimized_filter_parsers
47
+ if or_filter_parser
48
+ filter_parsers.inject([]) do |result, filter_parser|
49
+ if filter_parser != or_filter_parser && or_filter_parser.include?(filter_parser)
50
+ or_filter_parser.merge(filter_parser)
51
+ else
52
+ result << filter_parser
53
+ end
54
+
55
+ result
56
+ end
57
+ else
58
+ filter_parsers
59
+ end
60
+ end
61
+
62
+ def or_filter_parser
63
+ @or_filter_parser ||= filter_parsers.select { |filter_parser| filter_parser.or_attribute? }.first
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,25 +1,23 @@
1
- require File.expand_path(File.join('parsers', 'date_time_parser'), File.dirname(__FILE__))
2
- require File.expand_path(File.join('parsers', 'number_parser'), File.dirname(__FILE__))
3
- require File.expand_path(File.join('parsers', 'array_parser'), File.dirname(__FILE__))
4
- require File.expand_path(File.join('parsers', 'regex_parser'), File.dirname(__FILE__))
5
- require File.expand_path(File.join('parsers', 'boolean_and_nil_parser'), File.dirname(__FILE__))
1
+ require File.expand_path(File.join('parsers', 'filter_parser'), File.dirname(__FILE__))
2
+ require File.expand_path(File.join('parsers', 'filters_parser'), File.dirname(__FILE__))
6
3
 
7
4
  module Mongoid
8
5
  module QueryStringInterface
9
- CONDITIONAL_OPERATORS = [:all, :exists, :gte, :gt, :in, :lte, :lt, :ne, :nin, :size, :near, :within]
6
+ NORMAL_CONDITIONAL_OPERATORS = [:exists, :gte, :gt, :lte, :lt, :ne, :size, :near, :within]
7
+ ARRAY_CONDITIONAL_OPERATORS = [:all, :in, :nin]
8
+ CONDITIONAL_OPERATORS = ARRAY_CONDITIONAL_OPERATORS + NORMAL_CONDITIONAL_OPERATORS
10
9
  SORTING_OPERATORS = [:asc, :desc]
11
10
  OR_OPERATOR = :or
12
-
13
- ATTRIBUTE_REGEX = /(.*)\.(#{(CONDITIONAL_OPERATORS + SORTING_OPERATORS + [OR_OPERATOR]).join('|')})/
11
+
12
+ ATTRIBUTE_REGEX = /^(.*)\.(#{(CONDITIONAL_OPERATORS + SORTING_OPERATORS + [OR_OPERATOR]).join('|')})$/
13
+ OPERATOR_REGEX = /^.*\.(#{Mongoid::QueryStringInterface::CONDITIONAL_OPERATORS.join('|')})$/
14
+
14
15
  PAGER_ATTRIBUTES = [:total_entries, :total_pages, :per_page, :offset, :previous_page, :current_page, :next_page]
15
16
 
16
- PARSERS = [
17
- Mongoid::QueryStringInterface::Parsers::DateTimeParser.new,
18
- Mongoid::QueryStringInterface::Parsers::NumberParser.new,
19
- Mongoid::QueryStringInterface::Parsers::ArrayParser.new,
20
- Mongoid::QueryStringInterface::Parsers::RegexParser.new,
21
- Mongoid::QueryStringInterface::Parsers::BooleanAndNilParser.new
22
- ]
17
+ ORDER_BY_PARAMETER = :order_by
18
+ PAGINATION_PARAMTERS = [:per_page, :page]
19
+ FRAMEWORK_PARAMETERS = [:controller, :action, :format]
20
+ RESERVED_PARAMETERS = FRAMEWORK_PARAMETERS + PAGINATION_PARAMTERS + [ORDER_BY_PARAMETER]
23
21
 
24
22
  def filter_by(params={})
25
23
  params = hash_with_indifferent_access(params)
@@ -67,175 +65,47 @@ module Mongoid
67
65
  end
68
66
  end
69
67
 
70
- def default_filtering_options
71
- {}
72
- end
73
-
74
- def default_sorting_options
75
- []
76
- end
77
-
78
- def default_pagination_options
79
- { :per_page => 12, :page => 1 }
80
- end
68
+ def default_filtering_options; {}; end
69
+ def default_sorting_options; []; end
70
+ def default_pagination_options; { :per_page => 12, :page => 1 }; end
81
71
 
82
72
  protected
83
73
  def pagination_options(options)
84
- options.reverse_merge default_pagination_options
74
+ hash_with_indifferent_access(default_pagination_options).merge(options)
85
75
  end
86
76
 
87
77
  def filtering_options(options)
88
- default_filtering_options.merge(parse_operators(only_filtering(options)))
78
+ Mongoid::QueryStringInterface::Parsers::FiltersParser.new(
79
+ only_filtering(options),
80
+ default_filtering_options
81
+ ).parse
89
82
  end
90
83
 
91
84
  def sorting_options(options)
92
- options = only_sorting(options)
93
-
94
- sorting_options = []
95
- sorting_options.concat(parse_order_by(options))
96
- sorting_options.concat(parse_sorting(options))
97
-
98
- sorting_options.empty? ? default_sorting_options : sorting_options
99
- end
100
-
101
- def parse_operators(options)
102
- options.inject({}) do |result, item|
103
- key, value = item
104
-
105
- attribute = attribute_from(key)
106
-
107
- if or_attribute?(attribute)
108
- parse_or_attribute(attribute, key, value, result)
109
- else
110
- parse_normal_attribute(attribute, key, value, result)
111
- end
112
- end
113
- end
114
-
115
- def parse_or_attribute(attribute, key, value, result)
116
- result["$or"] = ::JSON.parse(unescape(value)).map do |filters|
117
- parse_operators(filters)
118
- end
119
-
120
- result
121
- end
122
-
123
- def parse_normal_attribute(attribute, key, value, result)
124
- operator = operator_from(key)
125
- value = parse_value(value, operator)
126
-
127
- if operator
128
- filter = { operator => value }
129
-
130
- if result.has_key?(attribute)
131
- result[attribute].merge!(filter)
132
- else
133
- result[attribute] = filter
134
- end
135
- else
136
- result[attribute] = value
137
- end
138
-
139
- result
140
- end
141
-
142
- def attribute_from(key)
143
- if key =~ ATTRIBUTE_REGEX
144
- $1.to_sym
145
- else
146
- key.to_sym
147
- end
148
- end
149
-
150
- def or_attribute?(attribute)
151
- OR_OPERATOR == attribute
152
- end
153
-
154
- def operator_from(key)
155
- if match = key.match(/.*\.(#{CONDITIONAL_OPERATORS.join('|')})/)
156
- "$#{match[1]}".to_sym
157
- end
158
- end
159
-
160
- def unescape(value)
161
- URI.unescape(value)
162
- end
163
-
164
- def parse_value(value, operator)
165
- if value.is_a?(String)
166
- value = unescape(value)
167
-
168
- PARSERS.each do |parser|
169
- return parser.parse(value) if parser.parseable?(value, operator)
170
- end
171
-
172
- return nil
173
- else
174
- value
175
- end
85
+ parse_order_by(options) || default_sorting_options
176
86
  end
177
87
 
178
88
  def hash_with_indifferent_access(params)
179
- params.is_a?(HashWithIndifferentAccess) ? params : HashWithIndifferentAccess.new(params)
89
+ params.is_a?(HashWithIndifferentAccess) ? params : params.with_indifferent_access
180
90
  end
181
91
 
182
92
  def only_filtering(options)
183
- options.except(*only_sorting(options).keys).except(:per_page, :page, :action, :controller, :format, :order_by)
184
- end
185
-
186
- def only_sorting(options)
187
- options.inject({}) do |result, item|
188
- key, value = item
189
- result[key] = value if sorting_parameter?(key, value)
190
- result
191
- end
192
- end
193
-
194
- def sorting_parameter?(key, value)
195
- order_by_parameter?(key) or sorting_key_parameter?(key) or sorting_value_parameter?(value)
196
- end
197
-
198
- def order_by_parameter?(key)
199
- key.to_s == 'order_by'
200
- end
201
-
202
- def sorting_key_parameter?(key)
203
- key.match(/(.*)\.(#{SORTING_OPERATORS.join('|')})/)
204
- end
205
-
206
- def sorting_value_parameter?(value)
207
- value.present? && SORTING_OPERATORS.include?(value.to_sym)
93
+ options.except(*RESERVED_PARAMETERS)
208
94
  end
209
95
 
210
96
  def parse_order_by(options)
211
- sorting_options = []
212
-
213
- if order_by = options.delete('order_by')
214
- if match = order_by.match(/(.*)\.(#{SORTING_OPERATORS.join('|')})/)
215
- sorting_options << match[1].to_sym.send(match[2])
216
- else
217
- sorting_options << order_by.to_sym.asc
97
+ if options.has_key?('order_by')
98
+ options['order_by'].split('|').map do |field|
99
+ sorting_operator_for(field)
218
100
  end
219
101
  end
220
-
221
- sorting_options
222
102
  end
223
-
224
- def parse_sorting(options)
225
- options.inject([]) do |result, item|
226
- key, value = item
227
-
228
- attribute = attribute_from(key)
229
- sorting_operator = sorting_operator_from(key)
230
103
 
231
- result << attribute.send(sorting_operator || value)
232
- result
233
- end
234
- end
235
-
236
- def sorting_operator_from(key)
237
- if match = key.match(/.*\.(#{SORTING_OPERATORS.join('|')})/)
238
- match[1].to_sym
104
+ def sorting_operator_for(field)
105
+ if match = field.match(/(.*)\.(#{SORTING_OPERATORS.join('|')})/)
106
+ match[1].to_sym.send(match[2])
107
+ else
108
+ field.to_sym.asc
239
109
  end
240
110
  end
241
111
  end
data/lib/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc
3
3
  module QueryStringInterface #:nodoc
4
- VERSION = "0.2.4"
4
+ VERSION = "0.3.0"
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid_query_string_interface
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 2
9
- - 4
10
- version: 0.2.4
7
+ - 3
8
+ - 0
9
+ version: 0.3.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Vicente Mundim
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-03-21 00:00:00 -03:00
17
+ date: 2011-03-29 00:00:00 -03:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- hash: 11
30
28
  segments:
31
29
  - 1
32
30
  - 4
@@ -42,7 +40,6 @@ dependencies:
42
40
  requirements:
43
41
  - - ~>
44
42
  - !ruby/object:Gem::Version
45
- hash: 7712058
46
43
  segments:
47
44
  - 2
48
45
  - 0
@@ -59,7 +56,6 @@ dependencies:
59
56
  requirements:
60
57
  - - ">="
61
58
  - !ruby/object:Gem::Version
62
- hash: 3
63
59
  segments:
64
60
  - 2
65
61
  - 3
@@ -75,7 +71,6 @@ dependencies:
75
71
  requirements:
76
72
  - - ">="
77
73
  - !ruby/object:Gem::Version
78
- hash: 11
79
74
  segments:
80
75
  - 0
81
76
  - 5
@@ -96,6 +91,8 @@ files:
96
91
  - lib/mongoid/parsers/array_parser.rb
97
92
  - lib/mongoid/parsers/boolean_and_nil_parser.rb
98
93
  - lib/mongoid/parsers/date_time_parser.rb
94
+ - lib/mongoid/parsers/filter_parser.rb
95
+ - lib/mongoid/parsers/filters_parser.rb
99
96
  - lib/mongoid/parsers/number_parser.rb
100
97
  - lib/mongoid/parsers/regex_parser.rb
101
98
  - lib/mongoid/query_string_interface.rb
@@ -119,7 +116,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
116
  requirements:
120
117
  - - ">="
121
118
  - !ruby/object:Gem::Version
122
- hash: 3
123
119
  segments:
124
120
  - 0
125
121
  version: "0"
@@ -128,7 +124,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
124
  requirements:
129
125
  - - ">="
130
126
  - !ruby/object:Gem::Version
131
- hash: 23
132
127
  segments:
133
128
  - 1
134
129
  - 3