rack-reducer 0.1.2 → 1.0.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.
- 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.
|