rack-reducer 0.1.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/rack/reducer.rb +0 -3
- data/lib/rack/reducer/middleware.rb +1 -2
- data/lib/rack/reducer/parser.rb +8 -4
- data/lib/rack/reducer/reduction.rb +6 -8
- data/lib/rack/reducer/refinements.rb +16 -16
- data/lib/rack/reducer/version.rb +5 -0
- data/spec/behavior.rb +1 -1
- data/spec/benchmarks.rb +28 -43
- data/spec/spec_helper.rb +1 -0
- metadata +39 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0be5dfa4acf3c9a2c7755c67f2bbc15a2126b5d3
|
4
|
+
data.tar.gz: 6bd09c026cd5e5b9fb1d8ac0425d2e525afb3a36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e03f7c4766706254c287c7dbb0b664cf29d8c3b7d1e210189d4c17a9cd3a013c579d4e5ee2d0cda56cbf146e639d7515aff3092cb6832621e058375316a2d692
|
7
|
+
data.tar.gz: 15c82a76f5a7218393656ddb4abfaa5584bc11b483326452d08ff16a4a9c3efdecbd07ed810af51401a03b07a95dadd89b76199dfc4564afb04c1f4db9a7b2ec
|
data/lib/rack/reducer.rb
CHANGED
data/lib/rack/reducer/parser.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Rack
|
4
2
|
module Reducer
|
5
3
|
# convert params from Sinatra, Rails, Roda, etc into a symbol hash
|
6
4
|
module Parser
|
7
5
|
def self.call(data)
|
8
|
-
data.is_a?(Hash) ? data : hashify(data)
|
6
|
+
data.is_a?(Hash) ? symbolize(data) : hashify(data)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.symbolize(data)
|
10
|
+
data.each_with_object({}) do |(key, val), hash|
|
11
|
+
hash[key.to_sym] = val.is_a?(Hash) ? symbolize(val) : val
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
15
|
# turns out a Rails params hash is not really a hash
|
@@ -13,7 +17,7 @@ module Rack
|
|
13
17
|
# are automatically sanitized by the lambda keywords
|
14
18
|
def self.hashify(data)
|
15
19
|
fn = %i[to_unsafe_h to_h].find { |name| data.respond_to?(name) }
|
16
|
-
data.send(fn)
|
20
|
+
symbolize(data.send(fn))
|
17
21
|
end
|
18
22
|
end
|
19
23
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require_relative 'refinements'
|
4
2
|
require_relative 'parser'
|
5
3
|
|
@@ -8,7 +6,7 @@ module Rack
|
|
8
6
|
# call `reduce` on a params hash, filtering data via lambdas with
|
9
7
|
# matching keyword arguments
|
10
8
|
class Reduction
|
11
|
-
using Refinements #
|
9
|
+
using Refinements # define Proc#required_argument_names, #satisfies?, etc
|
12
10
|
|
13
11
|
DEFAULTS = {
|
14
12
|
dataset: [],
|
@@ -18,7 +16,7 @@ module Rack
|
|
18
16
|
|
19
17
|
def initialize(options)
|
20
18
|
@props = DEFAULTS.merge(options)
|
21
|
-
@params = Parser.call(@props[:params])
|
19
|
+
@params = Parser.call(@props[:params])
|
22
20
|
end
|
23
21
|
|
24
22
|
def reduce
|
@@ -27,10 +25,10 @@ module Rack
|
|
27
25
|
|
28
26
|
private
|
29
27
|
|
30
|
-
def apply_filter(data,
|
31
|
-
|
32
|
-
|
33
|
-
data.instance_exec(@params.slice(*
|
28
|
+
def apply_filter(data, filter)
|
29
|
+
return data unless filter.satisfies?(@params)
|
30
|
+
|
31
|
+
data.instance_exec(@params.slice(*filter.all_argument_names), &filter)
|
34
32
|
end
|
35
33
|
end
|
36
34
|
end
|
@@ -1,29 +1,29 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Rack
|
4
2
|
module Reducer
|
5
|
-
# refine
|
3
|
+
# refine Proc and hash in this scope only
|
6
4
|
module Refinements
|
7
|
-
refine Hash do
|
8
|
-
def symbolize_keys
|
9
|
-
each_with_object({}) do |(key, val), hash|
|
10
|
-
hash[key.to_sym] = val.is_a?(Hash) ? val.symbolize_keys : val
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def satisfies?(requirements)
|
15
|
-
slice(*requirements).keys.to_set == requirements
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
5
|
refine Proc do
|
20
6
|
def required_argument_names
|
21
|
-
parameters.select { |
|
7
|
+
parameters.select { |type, _| type == :keyreq }.map(&:last)
|
22
8
|
end
|
23
9
|
|
24
10
|
def all_argument_names
|
25
11
|
parameters.map(&:last)
|
26
12
|
end
|
13
|
+
|
14
|
+
def satisfies?(params)
|
15
|
+
keywords = required_argument_names
|
16
|
+
params.slice(*keywords).keys.to_set == keywords.to_set
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# backport Hash#slice for older rubies
|
21
|
+
unless {}.respond_to?(:slice)
|
22
|
+
refine Hash do
|
23
|
+
def slice(*keys)
|
24
|
+
[keys, values_at(*keys)].transpose.select { |_k, val| val }.to_h
|
25
|
+
end
|
26
|
+
end
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/spec/behavior.rb
CHANGED
data/spec/benchmarks.rb
CHANGED
@@ -1,56 +1,41 @@
|
|
1
|
-
|
2
|
-
require_relative 'fixtures'
|
1
|
+
require_relative 'spec_helper'
|
3
2
|
require 'sinatra/base'
|
4
3
|
require 'json'
|
5
4
|
require 'benchmark/ips'
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@artists = @artists.grep(:genre, "%#{genre}%", case_insensitive: true)
|
12
|
-
end
|
13
|
-
if (name = params[:name])
|
14
|
-
@artists = @artists.grep(:name, "%#{name}%", case_insensitive: true)
|
15
|
-
end
|
16
|
-
|
17
|
-
@artists.to_json
|
6
|
+
Conditionals = lambda do |params = {}|
|
7
|
+
@artists = DB[:artists]
|
8
|
+
if (genre = params[:genre])
|
9
|
+
@artists = @artists.grep(:genre, "%#{genre}%", case_insensitive: true)
|
18
10
|
end
|
11
|
+
if (name = params[:name])
|
12
|
+
@artists = @artists.grep(:name, "%#{name}%", case_insensitive: true)
|
13
|
+
end
|
14
|
+
|
15
|
+
@artists.to_json
|
16
|
+
end
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
Reduction = lambda do |params = {}|
|
19
|
+
@artists = Rack::Reducer.call(params, dataset: DB[:artists], filters: [
|
20
|
+
->(genre:) { grep(:genre, "%#{genre}%", case_insensitive: true) },
|
21
|
+
->(name:) { grep(:name, "%#{name}%", case_insensitive: true) },
|
22
|
+
])
|
25
23
|
|
26
|
-
|
27
|
-
end
|
24
|
+
@artists.to_json
|
28
25
|
end
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
bm.report('reduction, empty params') do
|
39
|
-
get '/reduction'
|
40
|
-
end
|
41
|
-
bm.compare!
|
42
|
-
end
|
27
|
+
Benchmark.ips(3) do |bm|
|
28
|
+
bm.report('conditionals, empty params') { Conditionals.call }
|
29
|
+
|
30
|
+
bm.report('reduction, empty params') { Reduction.call }
|
31
|
+
|
32
|
+
bm.report('conditionals, full params') do
|
33
|
+
Conditionals.call({ name: 'blake', genre: 'electric' })
|
43
34
|
end
|
44
35
|
|
45
|
-
|
46
|
-
|
47
|
-
bm.report('conditionals, full params') do
|
48
|
-
get '/conditionals?name=blake&genre=electronic'
|
49
|
-
end
|
50
|
-
bm.report('reduction, full params') do
|
51
|
-
get '/reduction?name=blake&genre=electronic'
|
52
|
-
end
|
53
|
-
bm.compare!
|
54
|
-
end
|
36
|
+
bm.report('reduction, full params') do
|
37
|
+
Reduction.call({ name: 'blake', genre: 'electric' })
|
55
38
|
end
|
39
|
+
|
40
|
+
bm.compare!
|
56
41
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-reducer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Frank
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,42 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1'
|
19
|
+
version: '1.16'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1'
|
26
|
+
version: '1.16'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: benchmark-ips
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '2'
|
33
|
+
version: '2.7'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '2'
|
40
|
+
version: '2.7'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: pry
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '0.11'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '0.11'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: hanami
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '3'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.61'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0.61'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
168
|
name: sequel
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,6 +206,20 @@ dependencies:
|
|
192
206
|
- - "~>"
|
193
207
|
- !ruby/object:Gem::Version
|
194
208
|
version: '1'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: yard
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0.9'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - "~>"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0.9'
|
195
223
|
- !ruby/object:Gem::Dependency
|
196
224
|
name: rack
|
197
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -215,7 +243,7 @@ dependencies:
|
|
215
243
|
description: Dynamically filter, sort, and paginate data via URL params, in any Rack
|
216
244
|
app.
|
217
245
|
email:
|
218
|
-
- chris.frank@
|
246
|
+
- chris.frank@future.com
|
219
247
|
executables: []
|
220
248
|
extensions: []
|
221
249
|
extra_rdoc_files: []
|
@@ -226,6 +254,7 @@ files:
|
|
226
254
|
- lib/rack/reducer/parser.rb
|
227
255
|
- lib/rack/reducer/reduction.rb
|
228
256
|
- lib/rack/reducer/refinements.rb
|
257
|
+
- lib/rack/reducer/version.rb
|
229
258
|
- spec/_hanami_example/apps/web/application.rb
|
230
259
|
- spec/_hanami_example/apps/web/config/routes.rb
|
231
260
|
- spec/_hanami_example/apps/web/controllers/artists/index.rb
|
@@ -288,7 +317,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
288
317
|
version: '0'
|
289
318
|
requirements: []
|
290
319
|
rubyforge_project:
|
291
|
-
rubygems_version: 2.
|
320
|
+
rubygems_version: 2.4.5.5
|
292
321
|
signing_key:
|
293
322
|
specification_version: 4
|
294
323
|
summary: Dynamically filter data via URL params, in any Rack app.
|