mongoid_query_string_interface 0.2.4 → 0.3.0

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.
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