sorted 2.0.3 → 2.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47e5b8db73e27b5130e62753c00ec308e6c6886d
4
- data.tar.gz: 4c8abeb0e9399f5d2558d202597199ed8d236bea
3
+ metadata.gz: b9b0ab137af7f8964eb8b6d8bee93e782fae7dce
4
+ data.tar.gz: 373d2c35b43cdddecb7d0eb1e0b60b6cd2ebcbb0
5
5
  SHA512:
6
- metadata.gz: a1974de003bae9e48872f9652f209c5c374c0432d29635f1e169ef52ff3a0e626adff2bd2a8fa23ae583fe49cb98534e834ba82f36b1c285c456179f614ecb93
7
- data.tar.gz: f9d8cba70836197f131ce03c3c36c35318284842d8a40aeb2ae3b4815d411c8e142949900257541b986be0c47f6ff97a06d3c0d5de7709aff3630ad15464f394
6
+ metadata.gz: 53e9a1614a66a52f42ec5b219c25927978c410ae43ce4eb12cd0facb1be64c2e64cb2dba457909043f4f12320a04e3313336e60d1be7be5d57e817caf5656c4d
7
+ data.tar.gz: 57eaad9eb987b624cebe8f320a786e541450d4f24424a31f41153f233d0e12f55f38c8d8eb73edb045117dc7faccb2f4192f64077857cc1b8eb62f2589377c8d
data/.gitignore CHANGED
@@ -20,5 +20,6 @@ pkg
20
20
  .rvmrc
21
21
  Gemfile.lock
22
22
  .bundle
23
+ doc/*
23
24
 
24
25
  ## PROJECT::SPECIFIC
@@ -1,7 +1,4 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
- Style/Blocks:
4
- Enabled: false
5
-
6
3
  Style/WordArray:
7
4
  MinSize: 2
@@ -1,5 +1,5 @@
1
1
  # This configuration was generated by `rubocop --auto-gen-config`
2
- # on 2015-03-01 13:05:10 +1100 using RuboCop version 0.28.0.
2
+ # on 2015-09-23 09:55:31 +1000 using RuboCop version 0.28.0.
3
3
  # The point is for the user to remove these configuration records
4
4
  # one by one as the offenses are removed from the code base.
5
5
  # Note that changes in the inspected code, or installation of new
@@ -12,9 +12,9 @@ Metrics/AbcSize:
12
12
  # Offense count: 1
13
13
  # Configuration parameters: CountComments.
14
14
  Metrics/ClassLength:
15
- Max: 103
15
+ Max: 130
16
16
 
17
- # Offense count: 12
17
+ # Offense count: 18
18
18
  # Configuration parameters: AllowURI, URISchemes.
19
19
  Metrics/LineLength:
20
20
  Max: 131
@@ -24,7 +24,7 @@ Metrics/LineLength:
24
24
  Metrics/MethodLength:
25
25
  Max: 13
26
26
 
27
- # Offense count: 8
27
+ # Offense count: 9
28
28
  Style/Documentation:
29
29
  Enabled: false
30
30
 
@@ -37,3 +37,7 @@ Style/For:
37
37
  # Configuration parameters: MaxLineLength.
38
38
  Style/IfUnlessModifier:
39
39
  Enabled: false
40
+
41
+ # Offense count: 3
42
+ Style/OpMethod:
43
+ Enabled: false
data/README.md CHANGED
@@ -10,6 +10,8 @@ attributes in weird and wonderful ways.
10
10
  The secret sauce is the `Sorted::Set` object, in this example we 'toggle' email:
11
11
 
12
12
  ```ruby
13
+ require 'sorted/set'
14
+
13
15
  a = Sorted::Set.new([['email', 'asc'], ['name', 'asc']])
14
16
  b = Sorted::Set.new([['email', 'asc'], ['phone', 'asc']])
15
17
 
@@ -26,6 +28,8 @@ when you sort by various columns, `Sorted::Set` pretty much just does that.
26
28
  Parsers return a `Sorted::Set` that can then be used by an encoder:
27
29
 
28
30
  ```ruby
31
+ require 'sorted/uri_query'
32
+
29
33
  set = Sorted::URIQuery.parse('name_asc!email_asc')
30
34
  Sorted::SQLQuery.encode(set) #=> 'name ASC email ASC'
31
35
  ```
@@ -1,274 +1,2 @@
1
1
  module Sorted
2
- class Set
3
- include Enumerable
4
- include Comparable
5
-
6
- def initialize(set = [])
7
- @set = set
8
- end
9
-
10
- def each(&block)
11
- @set.each(&block)
12
- end
13
-
14
- ##
15
- # Gets the keys from the array pairs
16
- #
17
- # set = [["email", "name"], ["desc", "desc"]]
18
- # set.transpose #=> [["email", "name"], ["desc", "desc"]]
19
- # set.transpose.first #=> ["email", "name"]
20
-
21
- def keys
22
- @set.transpose.first || []
23
- end
24
-
25
- ##
26
- # Returns a resulting set with specific keys flipped
27
- #
28
- # a = Sorted::Set.new([['email', 'asc'], ['name', 'asc']])
29
- # b = Sorted::Set.new([['email', 'asc'], ['phone', 'asc']])
30
- # s = a.direction_intersect(b)
31
- # s.to_a #=> [['email', 'desc'], ['phone', 'asc'], ['name', 'asc']]
32
-
33
- def direction_intersect(other)
34
- self.class.new.tap do |memo|
35
- unless other.keys.empty?
36
- a(memo, other)
37
- b(memo, other)
38
- end
39
- c(memo)
40
- d(memo, other)
41
- end
42
- end
43
-
44
- def -(other)
45
- self.class.new.tap do |memo|
46
- each do |a|
47
- b = other.assoc(a.first)
48
- next if b
49
- memo << a
50
- end
51
- end
52
- end
53
-
54
- def +(other)
55
- self.class.new(@set + other.to_a)
56
- end
57
-
58
- def <<(other)
59
- self.class.new(@set << other.to_a)
60
- end
61
-
62
- def select(&block)
63
- self.class.new(@set.select(&block))
64
- end
65
-
66
- def reject(&block)
67
- self.class.new(@set.reject(&block))
68
- end
69
-
70
- def <=>(other)
71
- @set <=> other.to_a
72
- end
73
-
74
- def uniq
75
- self.class.new(@set.uniq)
76
- end
77
-
78
- def assoc(o)
79
- @set.assoc(o)
80
- end
81
-
82
- def at(i)
83
- @set.at(i)
84
- end
85
-
86
- def to_a
87
- @set
88
- end
89
-
90
- def to_hash
91
- @set.inject({}) { |a, e| a.merge(Hash[e[0], e[1]]) }
92
- end
93
-
94
- private
95
-
96
- # If the order of keys match upto the size of the set then flip them
97
- def a(memo, other)
98
- if keys == other.keys.take(keys.size)
99
- keys.each do |order|
100
- if other.keys.include?(order)
101
- memo << [order, flip_direction(other.assoc(order).last)]
102
- end
103
- end
104
- else
105
- keys.each do |order|
106
- if other.keys.include?(order)
107
- memo << other.assoc(order)
108
- end
109
- end
110
- end
111
- end
112
-
113
- # Add items from other that are common and not already added
114
- def b(memo, other)
115
- other.keys.each do |sort|
116
- if keys.include?(sort) && !memo.keys.include?(sort)
117
- memo << other.assoc(sort)
118
- end
119
- end
120
- end
121
-
122
- # Add items not in memo
123
- def c(memo)
124
- each do |order|
125
- unless memo.keys.include?(order[0])
126
- memo << order
127
- end
128
- end
129
- end
130
-
131
- # Add items from other not in memo
132
- def d(memo, other)
133
- other.each do |sort|
134
- unless memo.keys.include?(sort[0])
135
- memo << sort
136
- end
137
- end
138
- end
139
-
140
- def flip_direction(direction)
141
- case direction
142
- when 'asc' then 'desc'
143
- when 'desc'then 'asc'
144
- end
145
- end
146
- end
147
-
148
- module Parse
149
- def split(raw, delim, &block)
150
- return Set.new if raw.nil?
151
- raw.to_s.split(delim).inject(Set.new, &block)
152
- end
153
-
154
- def parse_match(m)
155
- [(m[2].nil? ? m[1] : m[2]), (m[3].nil? ? 'asc' : m[3].downcase)]
156
- end
157
- end
158
-
159
- class URIQuery
160
- extend Parse
161
-
162
- REGEXP = /(([a-z0-9._]+)_([asc|desc]+)|[a-z0-9._]+)/i
163
-
164
- def self.parse(raw)
165
- split(raw, /!/) do |set, part|
166
- m = part.match(REGEXP)
167
- next unless m
168
- set << parse_match(m)
169
- end
170
- end
171
-
172
- def self.encode(set)
173
- set.map { |a| a.join('_') }.join('!')
174
- end
175
- end
176
-
177
- class SQLQuery
178
- extend Parse
179
-
180
- REGEXP = /(([a-z0-9._]+)\s([asc|desc]+)|[a-z0-9._]+)/i
181
-
182
- def self.parse(raw)
183
- split(raw, /,/) do |set, part|
184
- m = part.match(REGEXP)
185
- next unless m
186
- set << parse_match(m)
187
- end
188
- end
189
-
190
- def self.encode(set, quote_proc = ->(f) { f })
191
- set.map { |a| "#{column(a[0], quote_proc)} #{a[1].upcase}" }.join(', ')
192
- end
193
-
194
- def self.column(parts, quote_proc)
195
- parts.split('.').map { |frag| quote_proc.call(frag) }.join('.')
196
- end
197
- private_class_method :column
198
- end
199
-
200
- class JSONQuery
201
- extend Parse
202
-
203
- JSON_TO_SORTED = { 1 => 'asc', -1 => 'desc' }
204
- SORTED_TO_JSON = { 'asc' => 1, 'desc' => -1 }
205
-
206
- def self.parse(raw)
207
- Set.new(raw.map { |key, val| [key, JSON_TO_SORTED[val]] })
208
- end
209
-
210
- def self.encode(set)
211
- set.inject({}) { |a, e| a.merge(Hash[e[0], SORTED_TO_JSON[e[1]]]) }
212
- end
213
- end
214
-
215
- ##
216
- # Parses an Elasticsearch type set of order
217
- #
218
- # Parsing:
219
- #
220
- # params = [{ 'email' => {'order' => 'desc'}}]
221
- # set = Sorted::ElasticsearchQuery.parse(params)
222
- # set.to_a #=> [['email', 'desc']]
223
- #
224
- # Encoding:
225
- #
226
- # Sorted::ParamsQuery.encode(set) #=> [{ 'email' => {'order' => 'desc'}}]
227
- #
228
-
229
- class ElasticsearchQuery
230
- extend Parse
231
-
232
- def self.parse(raw)
233
- Set.new(raw.each_with_object([]) { |hash, a| a << [hash.first.first, hash.first.last['order']] })
234
- end
235
-
236
- def self.encode(set)
237
- set.to_a.each_with_object([]) { |f, a| a << { f.first => { 'order' => f.last } } }
238
- end
239
- end
240
-
241
- ##
242
- # Parses an array of decoded query params
243
- #
244
- # This parser/encoder uses an already decoded array of sort strings parsed by
245
- # a URI library.
246
- #
247
- # Parsing:
248
- #
249
- # params = ['phone_desc', 'name_asc']
250
- # set = Sorted::ParamsQuery.parse(params)
251
- # set.to_a #=> [['phone', 'desc'], ['name', asc']]
252
- #
253
- # Encoding:
254
- #
255
- # Sorted::ParamsQuery.encode(set) #=> ['phone_desc', 'name_asc']
256
-
257
- class ParamsQuery
258
- extend Parse
259
-
260
- REGEXP = /(([a-z0-9._]+)_([asc|desc]+)|[a-z0-9._]+)/i
261
-
262
- def self.parse(params)
263
- params.inject(Set.new) do |set, part|
264
- m = part.match(REGEXP)
265
- next unless m
266
- set << parse_match(m)
267
- end
268
- end
269
-
270
- def self.encode(set)
271
- set.map { |a| a.join('_') }
272
- end
273
- end
274
2
  end
@@ -0,0 +1,27 @@
1
+ require 'sorted/set'
2
+
3
+ module Sorted
4
+ ##
5
+ # Parses an Elasticsearch type set of order
6
+ #
7
+ # Parsing:
8
+ #
9
+ # params = [{ 'email' => {'order' => 'desc'}}]
10
+ # set = Sorted::ElasticsearchQuery.parse(params)
11
+ # set.to_a #=> [['email', 'desc']]
12
+ #
13
+ # Encoding:
14
+ #
15
+ # Sorted::ParamsQuery.encode(set) #=> [{ 'email' => {'order' => 'desc'}}]
16
+ #
17
+
18
+ class ElasticsearchQuery
19
+ def self.parse(raw)
20
+ Set.new(raw.each_with_object([]) { |hash, a| a << [hash.first.first, hash.first.last['order']] })
21
+ end
22
+
23
+ def self.encode(set)
24
+ set.to_a.each_with_object([]) { |f, a| a << { f.first => { 'order' => f.last } } }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ require 'sorted/set'
2
+
3
+ module Sorted
4
+ class JSONQuery
5
+ JSON_TO_SORTED = { 1 => 'asc', -1 => 'desc' }
6
+ SORTED_TO_JSON = { 'asc' => 1, 'desc' => -1 }
7
+
8
+ def self.parse(raw)
9
+ Set.new(raw.map { |key, val| [key, JSON_TO_SORTED[val]] })
10
+ end
11
+
12
+ def self.encode(set)
13
+ set.inject({}) { |a, e| a.merge(Hash[e[0], SORTED_TO_JSON[e[1]]]) }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ require 'sorted/set'
2
+ require 'sorted/parse'
3
+
4
+ module Sorted
5
+ ##
6
+ # Parses an array of decoded query params
7
+ #
8
+ # This parser/encoder uses an already decoded array of sort strings parsed by
9
+ # a URI library.
10
+ #
11
+ # Parsing:
12
+ #
13
+ # params = ['phone_desc', 'name_asc']
14
+ # set = Sorted::ParamsQuery.parse(params)
15
+ # set.to_a #=> [['phone', 'desc'], ['name', asc']]
16
+ #
17
+ # Encoding:
18
+ #
19
+ # Sorted::ParamsQuery.encode(set) #=> ['phone_desc', 'name_asc']
20
+
21
+ class ParamsQuery
22
+ extend Parse
23
+
24
+ REGEXP = /(([a-z0-9._]+)_([asc|desc]+)|[a-z0-9._]+)/i
25
+
26
+ def self.parse(params)
27
+ params.inject(Set.new) do |set, part|
28
+ m = part.match(REGEXP)
29
+ next unless m
30
+ set << parse_match(m)
31
+ end
32
+ end
33
+
34
+ def self.encode(set)
35
+ set.map { |a| a.join('_') }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ require 'sorted/set'
2
+
3
+ module Sorted
4
+ module Parse
5
+ def split(raw, delim, &block)
6
+ return Set.new if raw.nil?
7
+ raw.to_s.split(delim).inject(Set.new, &block)
8
+ end
9
+
10
+ def parse_match(m)
11
+ [(m[2].nil? ? m[1] : m[2]), (m[3].nil? ? 'asc' : m[3].downcase)]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,238 @@
1
+ module Sorted
2
+ class Set
3
+ include Enumerable
4
+ include Comparable
5
+
6
+ def initialize(ary = [])
7
+ @ary = ary
8
+ end
9
+
10
+ ##
11
+ # Calls the given block once for each element in self, passing that element
12
+ # as a parameter.
13
+ #
14
+ # An Enumerator is returned if no block is given.
15
+
16
+ def each
17
+ return to_enum(:each) unless block_given?
18
+ @ary.each { |item| yield item }
19
+ end
20
+
21
+ ##
22
+ # Returns the keys form the array pairs.
23
+ #
24
+ # set = Sorted::Set.new([["email", "desc"], ["name", "desc"]])
25
+ # set.keys #=> ["email", "name"]
26
+
27
+ def keys
28
+ @ary.transpose.first || []
29
+ end
30
+
31
+ ##
32
+ # Returns a new array containing elements common to the two arrays,
33
+ # excluding any duplicates.
34
+ #
35
+ # Any matching keys at matching indexes with the same order will have the
36
+ # order reversed.
37
+ #
38
+ # a = Sorted::Set.new([['email', 'asc'], ['name', 'asc']])
39
+ # b = Sorted::Set.new([['email', 'asc'], ['phone', 'asc']])
40
+ # s = a.direction_intersect(b)
41
+ # s.to_a #=> [['email', 'desc'], ['phone', 'asc'], ['name', 'asc']]
42
+
43
+ def direction_intersect(other_set)
44
+ self.class.new.tap do |memo|
45
+ unless other_set.keys.empty?
46
+ a(memo, other_set)
47
+ b(memo, other_set)
48
+ end
49
+ c(memo)
50
+ d(memo, other_set)
51
+ end
52
+ end
53
+
54
+ ##
55
+ # Array Difference - Returns a new set that is a copy of the original set,
56
+ # removing any items that also appear in +other_set+. The order is preserved
57
+ # from the original set.
58
+ #
59
+ # set = Sorted::Set.new(['email', 'desc'])
60
+ # other_set = Sorted::Set.new(['phone', 'asc'])
61
+ # set - other_set #=> #<Sorted::Set:0x007fafde1ead80>
62
+
63
+ def -(other_set)
64
+ self.class.new.tap do |memo|
65
+ each do |a|
66
+ b = other_set.assoc(a.first)
67
+ next if b
68
+ memo << a
69
+ end
70
+ end
71
+ end
72
+
73
+ ##
74
+ # Concatenation - Returns a new set built by concatenating the two sets
75
+ # together to produce a third set.
76
+ #
77
+ # set = Sorted::Set.new(['email', 'desc'])
78
+ # other_set = Sorted::Set.new(['phone', 'asc'])
79
+ # set + other_set #=> #<Sorted::Set:0x007fafde1ead80>
80
+
81
+ def +(other_set)
82
+ self.class.new(@ary + other_set.to_a)
83
+ end
84
+
85
+ ##
86
+ # Append - Pushes the given order array on to the end of this set. This
87
+ # expression returns the set itself, so several appends may be chained
88
+ # together.
89
+ #
90
+ # set = Sorted::Set.new(['name', 'asc'])
91
+ # set << ['email', 'desc'] << ['phone', 'asc']
92
+ # set.to_a #=> [['name', 'asc'], ['email', 'desc'], ['phone', 'asc']]
93
+
94
+ def <<(ary)
95
+ @ary << ary
96
+ self
97
+ end
98
+
99
+ ##
100
+ # Returns a new set containing all elements of self for which the given
101
+ # block returns a true value.
102
+ #
103
+ # If no block is given, an Enumerator is returned instead.
104
+
105
+ def select
106
+ return to_enum(:select) unless block_given?
107
+ self.class.new(@ary.select { |item| yield item })
108
+ end
109
+
110
+ ##
111
+ # Returns a new set containing the items in self for which the given block
112
+ # is not true.
113
+ #
114
+ # If no block is given, an Enumerator is returned instead.
115
+
116
+ def reject
117
+ return to_enum(:reject) unless block_given?
118
+ self.class.new(@ary.reject { |item| yield item })
119
+ end
120
+
121
+ ##
122
+ # Comparison - Returns an integer (-1, 0, or +1) if this array is less than,
123
+ # equal to, or greater than +other_set+.
124
+
125
+ def <=>(other_set)
126
+ @ary <=> other_set.to_a
127
+ end
128
+
129
+ ##
130
+ # Returns a new set by removing duplicate values in self.
131
+ #
132
+ # If a block is given, it will use the return value of the block for comparison.
133
+
134
+ def uniq
135
+ return self.class.new(@ary.uniq) unless block_given?
136
+ self.class.new(@ary.uniq { |item| yield item })
137
+ end
138
+
139
+ ##
140
+ # Searches through an array whose elements are also arrays comparing +item+
141
+ # with the first element of each contained array using +item+.==.
142
+ #
143
+ # Returns the first contained array that matches (that is, the first
144
+ # associated array), or nil if no match is found.
145
+
146
+ def assoc(item)
147
+ @ary.assoc(item)
148
+ end
149
+
150
+ ##
151
+ # Returns key, order array pair at index +index+
152
+
153
+ def at(index)
154
+ @ary.at(index)
155
+ end
156
+
157
+ ##
158
+ # Returns the underlying array for the set object.
159
+ #
160
+ # set = Sorted::Set.new(['name', 'asc'])
161
+ # set.to_a #=> [['name', 'asc']]
162
+
163
+ def to_a
164
+ @ary
165
+ end
166
+
167
+ ##
168
+ # Returns the result of interpreting ary as an array of [key, value] pairs.
169
+ #
170
+ # set = Sorted::Set.new([['email', 'asc']])
171
+ # set.to_h #=> { 'email' => 'asc' }
172
+
173
+ def to_h
174
+ @ary.inject({}) { |a, e| a.merge(Hash[e[0], e[1]]) }
175
+ end
176
+
177
+ ##
178
+ # Returns the number of elements in self. May be zero.
179
+
180
+ def length
181
+ @ary.length
182
+ end
183
+ alias_method :size, :length
184
+
185
+ private
186
+
187
+ # If the order of keys match upto the size of the set then flip them
188
+ def a(memo, other)
189
+ if keys == other.keys.take(keys.size)
190
+ keys.each do |order|
191
+ if other.keys.include?(order)
192
+ memo << [order, flip_direction(other.assoc(order).last)]
193
+ end
194
+ end
195
+ else
196
+ keys.each do |order|
197
+ if other.keys.include?(order)
198
+ memo << other.assoc(order)
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ # Add items from other that are common and not already added
205
+ def b(memo, other)
206
+ other.keys.each do |sort|
207
+ if keys.include?(sort) && !memo.keys.include?(sort)
208
+ memo << other.assoc(sort)
209
+ end
210
+ end
211
+ end
212
+
213
+ # Add items not in memo
214
+ def c(memo)
215
+ each do |order|
216
+ unless memo.keys.include?(order[0])
217
+ memo << order
218
+ end
219
+ end
220
+ end
221
+
222
+ # Add items from other not in memo
223
+ def d(memo, other)
224
+ other.each do |sort|
225
+ unless memo.keys.include?(sort[0])
226
+ memo << sort
227
+ end
228
+ end
229
+ end
230
+
231
+ def flip_direction(direction)
232
+ case direction
233
+ when 'asc' then 'desc'
234
+ when 'desc' then 'asc'
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,26 @@
1
+ require 'sorted/set'
2
+
3
+ module Sorted
4
+ class SQLQuery
5
+ extend Parse
6
+
7
+ REGEXP = /(([a-z0-9._]+)\s([asc|desc]+)|[a-z0-9._]+)/i
8
+
9
+ def self.parse(raw)
10
+ split(raw, /,/) do |set, part|
11
+ m = part.match(REGEXP)
12
+ next unless m
13
+ set << parse_match(m)
14
+ end
15
+ end
16
+
17
+ def self.encode(set, quote_proc = ->(f) { f })
18
+ set.map { |a| "#{column(a[0], quote_proc)} #{a[1].upcase}" }.join(', ')
19
+ end
20
+
21
+ def self.column(parts, quote_proc)
22
+ parts.split('.').map { |frag| quote_proc.call(frag) }.join('.')
23
+ end
24
+ private_class_method :column
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ require 'sorted/set'
2
+ require 'sorted/parse'
3
+
4
+ module Sorted
5
+ class URIQuery
6
+ extend Parse
7
+
8
+ REGEXP = /(([a-z0-9._]+)_([asc|desc]+)|[a-z0-9._]+)/i
9
+
10
+ def self.parse(raw)
11
+ split(raw, /!/) do |set, part|
12
+ m = part.match(REGEXP)
13
+ next unless m
14
+ set << parse_match(m)
15
+ end
16
+ end
17
+
18
+ def self.encode(set)
19
+ set.map { |a| a.join('_') }.join('!')
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,3 @@
1
1
  module Sorted
2
- VERSION = '2.0.3'
2
+ VERSION = '2.1.1'
3
3
  end
@@ -21,6 +21,6 @@ Gem::Specification.new do |s|
21
21
  s.add_development_dependency 'rubocop', '>= 0.28'
22
22
 
23
23
  s.files = `git ls-files`.split("\n")
24
- s.executables = `git ls-files`.split("\n").map { |f| f =~ /^bin\/(.*)/ ? Regexp.last_match[1] : nil }.compact
24
+ s.executables = `git ls-files`.split("\n").map { |f| f =~ %r{/^bin\/(.*)/} ? Regexp.last_match[1] : nil }.compact
25
25
  s.require_path = 'lib'
26
26
  end
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'sorted/elasticsearch_query'
4
+
3
5
  describe Sorted::ElasticsearchQuery, 'decode' do
4
6
  it 'should decode elasticsearch order hash to into set' do
5
7
  json = [{ 'email' => { 'order' => 'desc' } }, { 'phone' => { 'order' => 'asc' } }, { 'name' => { 'order' => 'desc' } }]
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'sorted/json_query'
4
+
3
5
  describe Sorted::JSONQuery, 'decode' do
4
6
  it 'should return a nice array from the order sql' do
5
7
  json = { 'email' => 1, 'phone' => 1, 'name' => -1 }
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'sorted/params_query'
4
+
3
5
  describe Sorted::ParamsQuery, 'decode' do
4
6
  it 'should return a set from an array of params' do
5
7
  params = %w(email_asc phone_asc name_desc)
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'sorted/set'
4
+
3
5
  describe Sorted::Set do
4
6
  it 'should bring phone to first order importance but not toggle ascendance' do
5
7
  orders = Sorted::Set.new([['email', 'asc'], ['phone', 'asc']])
@@ -69,7 +71,7 @@ describe Sorted::Set do
69
71
  set = Sorted::Set.new([['email', 'asc']])
70
72
  result = { 'email' => 'asc' }
71
73
 
72
- expect(set.to_hash).to eq(result)
74
+ expect(set.to_h).to eq(result)
73
75
  end
74
76
 
75
77
  it 'should return set when selecting items' do
@@ -83,4 +85,18 @@ describe Sorted::Set do
83
85
 
84
86
  expect(set.reject { true }.class).to eq(Sorted::Set)
85
87
  end
88
+
89
+ it 'should append value to set' do
90
+ set = Sorted::Set.new([['email', 'asc']])
91
+ set << ['name', 'asc'] << ['phone', 'asc']
92
+
93
+ expect(set.length).to eq(3)
94
+ expect(set.size).to eq(3)
95
+ end
96
+
97
+ it 'should return a unique set' do
98
+ set = Sorted::Set.new([['email', 'asc'], ['email', 'asc']])
99
+
100
+ expect(set.uniq.to_a).to eq([['email', 'asc']])
101
+ end
86
102
  end
@@ -2,4 +2,3 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
 
4
4
  require 'rspec'
5
- require 'sorted'
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'sorted/sql_query'
4
+
3
5
  describe Sorted::SQLQuery, 'decode' do
4
6
  it 'should return a nice array from the order sql' do
5
7
  sql = 'email ASC, phone ASC, name DESC'
@@ -41,9 +43,7 @@ describe Sorted::SQLQuery, 'encode' do
41
43
  end
42
44
  end
43
45
 
44
- let(:quoter) {
45
- ->(frag) { FakeConnection.quote_column_name(frag) }
46
- }
46
+ let(:quoter) { ->(frag) { FakeConnection.quote_column_name(frag) } }
47
47
 
48
48
  it 'should properly escape sql column names' do
49
49
  set = Sorted::Set.new([['users.name', 'desc']])
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'sorted/uri_query'
4
+
3
5
  describe Sorted::URIQuery, 'decode' do
4
6
  it 'should allow numbers, underscores and full stops in sort params' do
5
7
  uri = 'assessmentsTable.name_desc!users_300.name_5_desc'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorted
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rufus Post
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-17 00:00:00.000000000 Z
11
+ date: 2015-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -83,6 +83,13 @@ files:
83
83
  - README.md
84
84
  - Rakefile
85
85
  - lib/sorted.rb
86
+ - lib/sorted/elasticsearch_query.rb
87
+ - lib/sorted/json_query.rb
88
+ - lib/sorted/params_query.rb
89
+ - lib/sorted/parse.rb
90
+ - lib/sorted/set.rb
91
+ - lib/sorted/sql_query.rb
92
+ - lib/sorted/uri_query.rb
86
93
  - lib/sorted/version.rb
87
94
  - sorted.gemspec
88
95
  - spec/elasticsearch_query_spec.rb