salestation 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fab51d38331535ba91704962caed90aafe63239b
4
- data.tar.gz: f9a1cab5d37fb3af72a9db99f42d8021ed10211a
3
+ metadata.gz: f1b525e1ec3e904fe1121233b9c9334348df43d0
4
+ data.tar.gz: 8b74d25e23e0c52c214591b55ad8a347765e2b32
5
5
  SHA512:
6
- metadata.gz: d3a2ded9db7798961555d9cac8c478e09d701c60bd4a7ed66a56771c88a4989b7c16a7091a1c162f2ee117ac29408561be2552f6424e450c0f4f0dc1bbaa8562
7
- data.tar.gz: c48aa6527625c1635c9746e9a7c5201d3b31d46cdeeb323e3c88fa6bccb0258f25e2bb1c7e8a0028203d37ff3c23e1b185a26376d73127124e58df9b9768463a
6
+ metadata.gz: 4c90e2e8ca7df677c87888b70788c0ac1337e78beb4f777a4825d2a57d6cd5167a19e9e80b383732ba8a390400bc2127050c67a8429adf9d1c2d2dd90d5b84f3
7
+ data.tar.gz: 5a50bc06f24eda87d84955e84eeffc253c87b33729b5c3cdb797f0ac521037278ccb949e976f06bd2e5134adae4b9e99af52fee26e5afc9a10614d2f5adf0e70
data/README.md CHANGED
@@ -75,6 +75,50 @@ Salestation allows and recommends you to define your own custom errors. This is
75
75
  })
76
76
  ```
77
77
 
78
+ ### Using Extractors
79
+
80
+ Salestation provides extractors to fetch parameters from the request and pass them to the chain.
81
+ Available extractors are `BodyParamExtractor`, `QueryParamExtractor`, `ConstantInput`, `HeadersExtractor`.
82
+ Multiple extractors can be merged together. If two or more extractors use the same key, the value will be from the last extractor in the merge chain.
83
+
84
+ `coercions` can optionally be provided to `BodyParamExtractor` and `QueryParamExtractor`. These can be used to transform the values of the extracted parameters.
85
+
86
+ Define a route
87
+
88
+ ```ruby
89
+ include Salestation::Web::Extractors
90
+
91
+ post '/hello/:name' do |name|
92
+ coercions = {age: ->(age) { age.to_s }}
93
+
94
+ extractor = BodyParamExtractor[:age, coercions: coercions]
95
+ .merge(ConstantInput[name: name])
96
+ .merge(HeadersExtractor[{'authorization' => :auth}])
97
+
98
+ process extractor do |request|
99
+ HelloUser.call(request)
100
+ .map(Responses.to_ok)
101
+ end
102
+ end
103
+
104
+ ERROR_MAPPER = Salestation::Web::ErrorMapper.new
105
+
106
+ def process(extract_input, &process_request)
107
+ response = extract_input.call(request).match do
108
+ Success() do |value|
109
+ create_request(value)
110
+ .map(process_request)
111
+ .map_err(&ERROR_MAPPER.map)
112
+ end
113
+ Failure() do |value|
114
+ Result::Success(value)
115
+ end
116
+ end
117
+ rescue Salestation::Web::ErrorMapper::UndefinedErrorClass => exception
118
+ raise exception
119
+ end
120
+ ```
121
+
78
122
  ### Using a logger
79
123
 
80
124
  Salestation provides a rack logging middleware which can be used to log structured objects.
@@ -30,6 +30,7 @@ module Salestation
30
30
  end
31
31
  end
32
32
 
33
+ require_relative './web/extractors'
33
34
  require_relative './web/responses'
34
35
  require_relative './web/error_mapper'
35
36
  require_relative './result_helper'
@@ -0,0 +1,103 @@
1
+ module Salestation
2
+ class Web < Module
3
+ module Extractors
4
+ class InputExtractor
5
+ include Deterministic
6
+
7
+ def initialize(&block)
8
+ @block = block
9
+ end
10
+
11
+ def call(rack_request)
12
+ @block.call(rack_request)
13
+ end
14
+
15
+ def merge(other)
16
+ CombinedInputExtractor.new([self, other])
17
+ end
18
+ end
19
+
20
+ class CombinedInputExtractor
21
+ def initialize(extractors)
22
+ @extractors = extractors
23
+ end
24
+
25
+ def compose_seq(fns, input)
26
+ fns.reduce(Deterministic::Result::Success({})) do |result, fn|
27
+ result.map do |previous_value|
28
+ fn.call(input).map do |new_value|
29
+ Deterministic::Result::Success(yield(previous_value, new_value))
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def call(rack_request)
36
+ compose_seq(@extractors, rack_request) do |previous_input, new_input|
37
+ previous_input.merge(new_input)
38
+ end
39
+ end
40
+
41
+ def merge(other_extractor)
42
+ CombinedInputExtractor.new(@extractors + [other_extractor])
43
+ end
44
+ end
45
+
46
+ class HeadersExtractor
47
+ include Deterministic
48
+
49
+ def self.[](headers)
50
+ InputExtractor.new do |rack_request|
51
+ input = headers.map do |header, key|
52
+ value = rack_request.env["HTTP_#{header.upcase.tr('-', '_')}"]
53
+ next if value.nil?
54
+ [key, value]
55
+ end.compact.to_h
56
+
57
+ Result::Success(input)
58
+ end
59
+ end
60
+ end
61
+
62
+ class ParamExtractor
63
+ include Deterministic
64
+
65
+ def self.[](*keys, coercions: {}, rack_key:)
66
+ InputExtractor.new do |rack_request|
67
+ request_hash = rack_request.env[rack_key] || {}
68
+
69
+ input = keys
70
+ .select { |key| request_hash.key?(key.to_s) }
71
+ .map { |key| [key, request_hash[key.to_s]] }
72
+ .map { |key, value| coercions.key?(key) ? [key, coercions[key].call(value)] : [key, value] }
73
+ .to_h
74
+
75
+ Result::Success(input)
76
+ end
77
+ end
78
+ end
79
+
80
+ class QueryParamExtractor
81
+ def self.[](*keys, coercions: {})
82
+ ParamExtractor[*keys, coercions: coercions, rack_key: 'rack.request.query_hash']
83
+ end
84
+ end
85
+
86
+ class BodyParamExtractor
87
+ def self.[](*keys, coercions: {})
88
+ ParamExtractor[*keys, coercions: coercions, rack_key: 'rack.request.form_hash']
89
+ end
90
+ end
91
+
92
+ class ConstantInput
93
+ include Deterministic
94
+
95
+ def self.[](input)
96
+ InputExtractor.new do |**|
97
+ Result::Success(input)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
data/salestation.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "salestation"
7
- spec.version = "0.2.1"
7
+ spec.version = "0.3.0"
8
8
  spec.authors = ["SaleMove TechMovers"]
9
9
  spec.email = ["techmovers@salemove.com"]
10
10
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: salestation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SaleMove TechMovers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-26 00:00:00.000000000 Z
11
+ date: 2017-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -131,6 +131,7 @@ files:
131
131
  - lib/salestation/web.rb
132
132
  - lib/salestation/web/active_record_connection_management.rb
133
133
  - lib/salestation/web/error_mapper.rb
134
+ - lib/salestation/web/extractors.rb
134
135
  - lib/salestation/web/request_logger.rb
135
136
  - lib/salestation/web/responses.rb
136
137
  - lib/salestation/web/statsd_middleware.rb
@@ -155,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
156
  version: '0'
156
157
  requirements: []
157
158
  rubyforge_project:
158
- rubygems_version: 2.6.8
159
+ rubygems_version: 2.6.11
159
160
  signing_key:
160
161
  specification_version: 4
161
162
  summary: ''