request 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.travis.yml +17 -0
- data/Changelog.md +3 -0
- data/Gemfile +6 -0
- data/Gemfile.devtools +60 -0
- data/Guardfile +18 -0
- data/LICENSE +20 -0
- data/README.md +1 -0
- data/Rakefile +2 -0
- data/TODO +2 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +92 -0
- data/config/roodi.yml +26 -0
- data/config/yardstick.yml +2 -0
- data/lib/request.rb +183 -0
- data/lib/request/key.rb +29 -0
- data/lib/request/method.rb +40 -0
- data/lib/request/protocol.rb +47 -0
- data/lib/request/rack.rb +121 -0
- data/lib/request/routed.rb +20 -0
- data/request.gemspec +23 -0
- data/spec/shared/rack_env_accessor_behavior.rb +24 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/request/key/hash_spec.rb +9 -0
- data/spec/unit/request/rack/host_spec.rb +12 -0
- data/spec/unit/request/rack/if_modified_since_spec.rb +25 -0
- data/spec/unit/request/rack/path_info_spec.rb +10 -0
- data/spec/unit/request/rack/port_spec.rb +12 -0
- data/spec/unit/request/rack/protocol_spec.rb +18 -0
- data/spec/unit/request/rack/query_string_spec.rb +12 -0
- data/spec/unit/request/rack/request_method_spec.rb +18 -0
- metadata +186 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
language: ruby
|
2
|
+
script: 'bundle exec rake spec'
|
3
|
+
rvm:
|
4
|
+
- ree
|
5
|
+
- 1.8.7
|
6
|
+
- 1.9.2
|
7
|
+
- 1.9.3
|
8
|
+
- 2.0.0
|
9
|
+
- ruby-head
|
10
|
+
- jruby-18mode
|
11
|
+
- jruby-19mode
|
12
|
+
- jruby-head
|
13
|
+
- rbx-18mode
|
14
|
+
- rbx-19mode
|
15
|
+
notifications:
|
16
|
+
email:
|
17
|
+
- mbj@seonic.net
|
data/Changelog.md
ADDED
data/Gemfile
ADDED
data/Gemfile.devtools
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
group :development do
|
4
|
+
gem 'rake', '~> 10.0.4'
|
5
|
+
gem 'rspec', '~> 2.13.0'
|
6
|
+
gem 'yard', '~> 0.8.6.1'
|
7
|
+
end
|
8
|
+
|
9
|
+
group :yard do
|
10
|
+
gem 'kramdown', '~> 1.0.1'
|
11
|
+
end
|
12
|
+
|
13
|
+
group :guard do
|
14
|
+
gem 'guard', '~> 1.8.0'
|
15
|
+
gem 'guard-bundler', '~> 1.0.0'
|
16
|
+
gem 'guard-rspec', '~> 2.5.4'
|
17
|
+
|
18
|
+
# file system change event handling
|
19
|
+
gem 'listen', '~> 1.0.2'
|
20
|
+
gem 'rb-fchange', '~> 0.0.6', :require => false
|
21
|
+
gem 'rb-fsevent', '~> 0.9.3', :require => false
|
22
|
+
gem 'rb-inotify', '~> 0.9.0', :require => false
|
23
|
+
|
24
|
+
# notification handling
|
25
|
+
gem 'libnotify', '~> 0.8.0', :require => false
|
26
|
+
gem 'rb-notifu', '~> 0.0.4', :require => false
|
27
|
+
gem 'terminal-notifier-guard', '~> 1.5.3', :require => false
|
28
|
+
end
|
29
|
+
|
30
|
+
group :metrics do
|
31
|
+
gem 'backports', '~> 3.3', '>= 3.3.0'
|
32
|
+
gem 'coveralls', '~> 0.6.6'
|
33
|
+
gem 'flay', '~> 2.2.0'
|
34
|
+
gem 'flog', '~> 4.0.0'
|
35
|
+
gem 'reek', '~> 1.3.1', :git => 'https://github.com/troessner/reek.git'
|
36
|
+
gem 'simplecov', '~> 0.7.1'
|
37
|
+
gem 'yardstick', '~> 0.9.6'
|
38
|
+
|
39
|
+
platforms :ruby_19 do
|
40
|
+
gem 'yard-spellcheck', '~> 0.1.5'
|
41
|
+
end
|
42
|
+
|
43
|
+
platforms :mri_19, :rbx do
|
44
|
+
gem 'mutant', '~> 0.2.20'
|
45
|
+
end
|
46
|
+
|
47
|
+
platforms :rbx do
|
48
|
+
gem 'pelusa', '~> 0.2.2'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
group :benchmarks do
|
53
|
+
gem 'rbench', '~> 0.2.3'
|
54
|
+
end
|
55
|
+
|
56
|
+
platform :jruby do
|
57
|
+
group :jruby do
|
58
|
+
gem 'jruby-openssl', '~> 0.8.5'
|
59
|
+
end
|
60
|
+
end
|
data/Guardfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
guard :bundler do
|
4
|
+
watch('Gemfile')
|
5
|
+
end
|
6
|
+
|
7
|
+
guard :rspec do
|
8
|
+
# run all specs if the spec_helper or supporting files files are modified
|
9
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
10
|
+
watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec' }
|
11
|
+
|
12
|
+
# run unit specs if associated lib code is modified
|
13
|
+
watch(%r{\Alib/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}"] }
|
14
|
+
watch("lib/#{File.basename(File.expand_path('../', __FILE__))}.rb") { 'spec' }
|
15
|
+
|
16
|
+
# run a spec if it is modified
|
17
|
+
watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
|
18
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Markus Schirp
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
This is spiky, more to come.
|
data/Rakefile
ADDED
data/config/devtools.yml
ADDED
data/config/flay.yml
ADDED
data/config/flog.yml
ADDED
data/config/mutant.yml
ADDED
data/config/reek.yml
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
---
|
2
|
+
UncommunicativeParameterName:
|
3
|
+
accept: []
|
4
|
+
exclude: []
|
5
|
+
enabled: false # Todo enable
|
6
|
+
reject:
|
7
|
+
- !ruby/regexp /^.$/
|
8
|
+
- !ruby/regexp /[0-9]$/
|
9
|
+
- !ruby/regexp /[A-Z]/
|
10
|
+
TooManyMethods:
|
11
|
+
max_methods: 10 # Todo decrease to 10
|
12
|
+
exclude: []
|
13
|
+
enabled: true
|
14
|
+
max_instance_variables: 3
|
15
|
+
UncommunicativeMethodName:
|
16
|
+
accept: []
|
17
|
+
exclude: []
|
18
|
+
enabled: true
|
19
|
+
reject:
|
20
|
+
- !ruby/regexp /^[a-z]$/
|
21
|
+
- !ruby/regexp /[0-9]$/
|
22
|
+
- !ruby/regexp /[A-Z]/
|
23
|
+
LongParameterList:
|
24
|
+
max_params: 2
|
25
|
+
exclude: []
|
26
|
+
enabled: true
|
27
|
+
overrides: {}
|
28
|
+
FeatureEnvy:
|
29
|
+
exclude: []
|
30
|
+
enabled: true
|
31
|
+
ClassVariable:
|
32
|
+
exclude: []
|
33
|
+
enabled: true
|
34
|
+
BooleanParameter:
|
35
|
+
exclude: []
|
36
|
+
enabled: true
|
37
|
+
IrresponsibleModule:
|
38
|
+
exclude: []
|
39
|
+
enabled: false # Fix false positives and reenable
|
40
|
+
UncommunicativeModuleName:
|
41
|
+
accept: []
|
42
|
+
exclude: []
|
43
|
+
enabled: true
|
44
|
+
reject:
|
45
|
+
- !ruby/regexp /^.$/
|
46
|
+
- !ruby/regexp /[0-9]$/
|
47
|
+
NestedIterators:
|
48
|
+
ignore_iterators: []
|
49
|
+
exclude: []
|
50
|
+
enabled: true
|
51
|
+
max_allowed_nesting: 1
|
52
|
+
TooManyStatements:
|
53
|
+
max_statements: 8
|
54
|
+
exclude: []
|
55
|
+
enabled: true
|
56
|
+
DuplicateMethodCall:
|
57
|
+
allow_calls: []
|
58
|
+
exclude: []
|
59
|
+
enabled: true
|
60
|
+
max_calls: 1
|
61
|
+
UtilityFunction:
|
62
|
+
max_helper_calls: 0
|
63
|
+
exclude:
|
64
|
+
- Request#uid # Acceptable
|
65
|
+
enabled: true
|
66
|
+
Attribute:
|
67
|
+
exclude: []
|
68
|
+
enabled: false
|
69
|
+
UncommunicativeVariableName:
|
70
|
+
accept: []
|
71
|
+
exclude: []
|
72
|
+
enabled: false
|
73
|
+
reject:
|
74
|
+
- !ruby/regexp /^.$/
|
75
|
+
- !ruby/regexp /[0-9]$/
|
76
|
+
- !ruby/regexp /[A-Z]/
|
77
|
+
RepeatedConditional:
|
78
|
+
exclude: []
|
79
|
+
enabled: true
|
80
|
+
max_ifs: 1
|
81
|
+
DataClump:
|
82
|
+
exclude: []
|
83
|
+
enabled: true
|
84
|
+
max_copies: 2
|
85
|
+
min_clump_size: 2
|
86
|
+
ControlParameter:
|
87
|
+
exclude: []
|
88
|
+
enabled: true
|
89
|
+
LongYieldList:
|
90
|
+
max_params: 1
|
91
|
+
exclude: []
|
92
|
+
enabled: true
|
data/config/roodi.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
AbcMetricMethodCheck:
|
3
|
+
score: 12.2
|
4
|
+
AssignmentInConditionalCheck: {}
|
5
|
+
CaseMissingElseCheck: {}
|
6
|
+
ClassLineCountCheck:
|
7
|
+
line_count: 324
|
8
|
+
ClassNameCheck:
|
9
|
+
pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/
|
10
|
+
ClassVariableCheck: {}
|
11
|
+
CyclomaticComplexityBlockCheck:
|
12
|
+
complexity: 2
|
13
|
+
CyclomaticComplexityMethodCheck:
|
14
|
+
complexity: 4
|
15
|
+
EmptyRescueBodyCheck: {}
|
16
|
+
ForLoopCheck: {}
|
17
|
+
MethodLineCountCheck:
|
18
|
+
line_count: 8 # TODO decrease to 9
|
19
|
+
MethodNameCheck:
|
20
|
+
pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|<<|[+*&|-])\z/
|
21
|
+
ModuleLineCountCheck:
|
22
|
+
line_count: 376
|
23
|
+
ModuleNameCheck:
|
24
|
+
pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/
|
25
|
+
ParameterNumberCheck:
|
26
|
+
parameter_count: 4 # TODO decrease to 2
|
data/lib/request.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'concord'
|
2
|
+
require 'time'
|
3
|
+
require 'equalizer'
|
4
|
+
require 'abstract_type'
|
5
|
+
require 'adamantium'
|
6
|
+
require 'ice_nine'
|
7
|
+
require 'securerandom'
|
8
|
+
|
9
|
+
# Library namespace and abstract base class
|
10
|
+
class Request
|
11
|
+
|
12
|
+
KEYS = %W(
|
13
|
+
path_info protocol port request_method
|
14
|
+
host if_modified_since query_params query_params_hash
|
15
|
+
query_string content_length content_type body
|
16
|
+
).map(&:to_sym).freeze
|
17
|
+
|
18
|
+
METHODS = (KEYS + %W(rack_env get? post?)).map(&:to_sym).freeze
|
19
|
+
|
20
|
+
include Adamantium::Flat, AbstractType, Equalizer.new(*KEYS)
|
21
|
+
|
22
|
+
# Return unique id
|
23
|
+
#
|
24
|
+
# @return [String]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
#
|
28
|
+
def uid
|
29
|
+
SecureRandom.hex(6)
|
30
|
+
end
|
31
|
+
memoize :uid
|
32
|
+
|
33
|
+
# Return protocol
|
34
|
+
#
|
35
|
+
# @return [Protocol]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
#
|
39
|
+
abstract_method :protocol
|
40
|
+
|
41
|
+
# Return if modified since header
|
42
|
+
#
|
43
|
+
# @return [Time]
|
44
|
+
# if present
|
45
|
+
#
|
46
|
+
# @return [nil]
|
47
|
+
# otherwise
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
#
|
51
|
+
abstract_method :if_modified_since
|
52
|
+
|
53
|
+
# Return path info
|
54
|
+
#
|
55
|
+
# @return [String]
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
abstract_method :path_info
|
60
|
+
|
61
|
+
# Return host
|
62
|
+
#
|
63
|
+
# @return [String]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
#
|
67
|
+
abstract_method :host
|
68
|
+
|
69
|
+
# Return port
|
70
|
+
#
|
71
|
+
# @return [Integer]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
#
|
75
|
+
abstract_method :port
|
76
|
+
|
77
|
+
# Return request method
|
78
|
+
#
|
79
|
+
# @return [Method]
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
#
|
83
|
+
abstract_method :request_method
|
84
|
+
|
85
|
+
# Return query params
|
86
|
+
#
|
87
|
+
# @return [Array]
|
88
|
+
#
|
89
|
+
# @api private
|
90
|
+
#
|
91
|
+
abstract_method :query_params
|
92
|
+
|
93
|
+
# Return query params hash
|
94
|
+
#
|
95
|
+
# @return [Hash]
|
96
|
+
#
|
97
|
+
# @api private
|
98
|
+
#
|
99
|
+
def query_params_hash
|
100
|
+
query_params.each_with_object({}) do |(key, value), hash|
|
101
|
+
hash[key]=value
|
102
|
+
end
|
103
|
+
end
|
104
|
+
memoize :query_params_hash
|
105
|
+
|
106
|
+
# Return query string
|
107
|
+
#
|
108
|
+
# @return [String]
|
109
|
+
#
|
110
|
+
# @api private
|
111
|
+
#
|
112
|
+
abstract_method :query_string
|
113
|
+
|
114
|
+
# Return absolute uri
|
115
|
+
#
|
116
|
+
# @return [String]
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
#
|
120
|
+
def absolute_uri
|
121
|
+
"#{root_uri}#{path_info}"
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return absolute uri for path
|
125
|
+
#
|
126
|
+
# @param [Path]
|
127
|
+
#
|
128
|
+
# @return [String]
|
129
|
+
#
|
130
|
+
# @api private
|
131
|
+
#
|
132
|
+
def absolute_uri_path(path)
|
133
|
+
"#{root_uri}#{path}"
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return routed request
|
137
|
+
#
|
138
|
+
# @param [Hash] params
|
139
|
+
#
|
140
|
+
# @return [Request::Routed]
|
141
|
+
#
|
142
|
+
# @api private
|
143
|
+
#
|
144
|
+
def route(params)
|
145
|
+
Routed.new(self, params)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Return root uri
|
149
|
+
#
|
150
|
+
# @return [String]
|
151
|
+
#
|
152
|
+
# @api private
|
153
|
+
#
|
154
|
+
def root_uri
|
155
|
+
"#{protocol.name}://#{host_with_port}"
|
156
|
+
end
|
157
|
+
memoize :root_uri
|
158
|
+
|
159
|
+
# Return host with optional port
|
160
|
+
#
|
161
|
+
# Only returns port if protocols default port diffes from actual port.
|
162
|
+
#
|
163
|
+
# @return [String]
|
164
|
+
#
|
165
|
+
# @api private
|
166
|
+
#
|
167
|
+
def host_with_port
|
168
|
+
uhost, uport = self.host, self.port
|
169
|
+
if port != protocol.default_port
|
170
|
+
"#{uhost}:#{uport}"
|
171
|
+
else
|
172
|
+
uhost
|
173
|
+
end
|
174
|
+
end
|
175
|
+
memoize :host_with_port
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
require 'request/key'
|
180
|
+
require 'request/rack'
|
181
|
+
require 'request/routed'
|
182
|
+
require 'request/method'
|
183
|
+
require 'request/protocol'
|
data/lib/request/key.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
class Request
|
2
|
+
|
3
|
+
# A string with cashed #hash for faster hash access
|
4
|
+
class Key < ::String
|
5
|
+
|
6
|
+
# Return hash
|
7
|
+
#
|
8
|
+
# @return [Fixnum]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
attr_reader :hash
|
13
|
+
|
14
|
+
# Initialize object
|
15
|
+
#
|
16
|
+
# @param [String] string
|
17
|
+
#
|
18
|
+
# @return [undefined]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
def initialize(string)
|
23
|
+
@hash = string.hash
|
24
|
+
super(string)
|
25
|
+
freeze
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Request
|
2
|
+
# The request method of a request
|
3
|
+
class Method
|
4
|
+
include Adamantium, Concord.new(:verb)
|
5
|
+
|
6
|
+
private_class_method :new
|
7
|
+
|
8
|
+
ALL = []
|
9
|
+
ALL << HEAD = new('HEAD')
|
10
|
+
ALL << POST = new('POST')
|
11
|
+
ALL << GET = new('GET')
|
12
|
+
ALL << PUT = new('PUT')
|
13
|
+
ALL << DELETE = new('DELETE')
|
14
|
+
ALL.freeze
|
15
|
+
|
16
|
+
# Return verb
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
attr_reader :verb
|
23
|
+
|
24
|
+
INDEX = ALL.each_with_object({}) do |method, index|
|
25
|
+
index[method.verb]=method
|
26
|
+
end.freeze
|
27
|
+
|
28
|
+
# Return request method
|
29
|
+
#
|
30
|
+
# @param [String] verb
|
31
|
+
#
|
32
|
+
# @return [Method]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
#
|
36
|
+
def self.get(verb)
|
37
|
+
INDEX.fetch(verb)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Request
|
2
|
+
class Protocol
|
3
|
+
include Adamantium, Concord.new(:name, :default_port)
|
4
|
+
|
5
|
+
private_class_method :new
|
6
|
+
|
7
|
+
ALL = []
|
8
|
+
|
9
|
+
ALL << HTTP = new('http', 80)
|
10
|
+
ALL << HTTPS = new('https', 443)
|
11
|
+
|
12
|
+
# Return name
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
# Return default port
|
21
|
+
#
|
22
|
+
# @return [Fixnum]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
#
|
26
|
+
attr_reader :default_port
|
27
|
+
|
28
|
+
ALL.freeze
|
29
|
+
|
30
|
+
INDEX = ALL.each_with_object({}) do |protocol, index|
|
31
|
+
index[protocol.name] = protocol
|
32
|
+
end.freeze
|
33
|
+
|
34
|
+
# Return protocol for name
|
35
|
+
#
|
36
|
+
# @param [String] name
|
37
|
+
#
|
38
|
+
# @return [Protocol]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
def self.get(name)
|
43
|
+
INDEX.fetch(name)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/request/rack.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
class Request
|
2
|
+
# Rack request
|
3
|
+
class Rack < self
|
4
|
+
include Concord.new(:rack_env)
|
5
|
+
|
6
|
+
SERVER_PORT = Key.new('SERVER_PORT')
|
7
|
+
REQUEST_METHOD = Key.new('REQUEST_METHOD')
|
8
|
+
RACK_URL_SCHEME = Key.new('rack.url_scheme')
|
9
|
+
IF_MODIFIED_SINCE = Key.new('HTTP_IF_MODIFIED_SINCE')
|
10
|
+
CONTENT_LENGTH = Key.new('CONTENT_LENGTH')
|
11
|
+
|
12
|
+
# Declare accessor
|
13
|
+
#
|
14
|
+
# @param [Symbol] name
|
15
|
+
# @param [Key] key
|
16
|
+
#
|
17
|
+
# @return [undefined]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
def self.accessor(name, key)
|
22
|
+
define_method(name) do
|
23
|
+
access(key)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return http port
|
28
|
+
#
|
29
|
+
# @return [Fixnum]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
#
|
33
|
+
def port
|
34
|
+
@rack_env.fetch(SERVER_PORT).to_i(10)
|
35
|
+
end
|
36
|
+
memoize :port
|
37
|
+
|
38
|
+
# Return request protocol
|
39
|
+
#
|
40
|
+
# @return [Protocol]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
def protocol
|
45
|
+
Protocol.get(access(RACK_URL_SCHEME))
|
46
|
+
end
|
47
|
+
memoize :protocol
|
48
|
+
|
49
|
+
# Return request method
|
50
|
+
#
|
51
|
+
# @return [Method]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
#
|
55
|
+
def request_method
|
56
|
+
Method.get(access(REQUEST_METHOD))
|
57
|
+
end
|
58
|
+
memoize :request_method
|
59
|
+
|
60
|
+
# Return content length
|
61
|
+
#
|
62
|
+
# @return [Fixnum]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
#
|
66
|
+
def content_length
|
67
|
+
access(CONTENT_LENGTH).to_i(10)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return query params
|
71
|
+
#
|
72
|
+
# @return [Array]
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
#
|
76
|
+
def query_params
|
77
|
+
Addressable::URI.form_unencode(query_string)
|
78
|
+
end
|
79
|
+
memoize :query_params
|
80
|
+
|
81
|
+
# Return if modified since
|
82
|
+
#
|
83
|
+
# @return [Time]
|
84
|
+
# if present
|
85
|
+
#
|
86
|
+
# @return [nil]
|
87
|
+
# otherwise
|
88
|
+
#
|
89
|
+
# @api private
|
90
|
+
#
|
91
|
+
def if_modified_since
|
92
|
+
value = @rack_env.fetch(IF_MODIFIED_SINCE) { return }
|
93
|
+
begin
|
94
|
+
Time.httpdate(value)
|
95
|
+
rescue ArgumentError
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
memoize :if_modified_since
|
100
|
+
|
101
|
+
accessor(:path_info, Key.new('PATH_INFO') )
|
102
|
+
accessor(:host, Key.new('SERVER_NAME') )
|
103
|
+
accessor(:query_string, Key.new('QUERY_STRING'))
|
104
|
+
accessor(:content_type, Key.new('CONTENT_TYPE'))
|
105
|
+
accessor(:body, Key.new('rack.input'))
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# Return value for key
|
110
|
+
#
|
111
|
+
# @param [Key] key
|
112
|
+
#
|
113
|
+
# @return [Object]
|
114
|
+
#
|
115
|
+
# @api private
|
116
|
+
#
|
117
|
+
def access(key)
|
118
|
+
@rack_env.fetch(key)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Request
|
2
|
+
# A routed request with routing params
|
3
|
+
#
|
4
|
+
# FIXME: I do not like this, need to come up with something much better!
|
5
|
+
#
|
6
|
+
# Violates LSP.
|
7
|
+
#
|
8
|
+
# Remove this once "Dispatch" class in Joy is ready.
|
9
|
+
#
|
10
|
+
class Routed < self
|
11
|
+
include Concord.new(:request, :routing_params)
|
12
|
+
|
13
|
+
METHODS.each do |name|
|
14
|
+
define_method(name) do
|
15
|
+
@request.public_send(name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
data/request.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = 'request'
|
5
|
+
gem.version = '0.0.2'
|
6
|
+
gem.authors = [ 'Markus Schirp' ]
|
7
|
+
gem.email = [ 'mbj@seonic.net' ]
|
8
|
+
gem.description = 'HTTP request porofication'
|
9
|
+
gem.summary = gem.description
|
10
|
+
gem.homepage = 'https://github.com/mbj/response'
|
11
|
+
|
12
|
+
gem.require_paths = [ 'lib' ]
|
13
|
+
gem.files = `git ls-files`.split("\n")
|
14
|
+
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
15
|
+
gem.extra_rdoc_files = %w[LICENSE README.md TODO]
|
16
|
+
|
17
|
+
gem.add_dependency('backports', [ '~> 3.0', '>= 3.0.3' ])
|
18
|
+
gem.add_dependency('concord', '~> 0.1.0')
|
19
|
+
gem.add_dependency('ice_nine', '~> 0.7.0')
|
20
|
+
gem.add_dependency('adamantium', '~> 0.0.7')
|
21
|
+
gem.add_dependency('equalizer', '~> 0.0.5')
|
22
|
+
gem.add_dependency('abstract_type', '~> 0.0.5')
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
shared_examples_for 'a rack env accessor' do
|
2
|
+
let(:rack_key_value) { :Value }
|
3
|
+
|
4
|
+
let(:default_env) do
|
5
|
+
{
|
6
|
+
'REQUEST_METHOD' => 'GET',
|
7
|
+
'SERVER_NAME' => 'example.org',
|
8
|
+
'SERVER_PORT' => '80',
|
9
|
+
'PATH_INFO' => '/',
|
10
|
+
'rack.url_scheme' => 'http'
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:expected_value) { rack_key_value }
|
15
|
+
|
16
|
+
let(:env) { default_env.merge(rack_key => rack_key_value) }
|
17
|
+
|
18
|
+
it { should eql(expected_value) }
|
19
|
+
|
20
|
+
it 'should not freeze the input env' do
|
21
|
+
subject
|
22
|
+
env.frozen?.should be(false)
|
23
|
+
end
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Request::Rack, '#if_modified_since' do
|
4
|
+
subject { object.if_modified_since }
|
5
|
+
|
6
|
+
let(:object) { described_class.new(env) }
|
7
|
+
let(:rack_key) { 'HTTP_IF_MODIFIED_SINCE' }
|
8
|
+
|
9
|
+
context 'if value is decodable' do
|
10
|
+
it_should_behave_like 'a rack env accessor' do
|
11
|
+
|
12
|
+
# Strip milliseconds
|
13
|
+
let(:time) { Time.httpdate(Time.now.httpdate) }
|
14
|
+
let(:rack_key_value) { time.httpdate }
|
15
|
+
let(:expected_value) { time }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'if value is not decodable' do
|
20
|
+
it_should_behave_like 'a rack env accessor' do
|
21
|
+
let(:rack_key_value) { 'foo' }
|
22
|
+
let(:expected_value) { nil }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Request::Rack, '#port' do
|
4
|
+
subject { object.port }
|
5
|
+
|
6
|
+
it_should_behave_like 'a rack env accessor' do
|
7
|
+
let(:object) { described_class.new(env) }
|
8
|
+
let(:rack_key) { 'SERVER_PORT' }
|
9
|
+
let(:rack_key_value) { '80' }
|
10
|
+
let(:expected_value) { 80 }
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Request::Rack, '#protocol' do
|
4
|
+
subject { object.protocol }
|
5
|
+
|
6
|
+
Request::Protocol::ALL.each do |protocol|
|
7
|
+
it_should_behave_like 'a rack env accessor' do
|
8
|
+
|
9
|
+
let(:object) { described_class.new(env) }
|
10
|
+
let(:rack_key) { 'rack.url_scheme' }
|
11
|
+
let(:rack_key_value) { protocol.name }
|
12
|
+
let(:expected_value) { protocol }
|
13
|
+
|
14
|
+
#let(:expected_method)
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Request::Rack, '#request_method' do
|
4
|
+
subject { object.request_method }
|
5
|
+
|
6
|
+
Request::Method::ALL.each do |method|
|
7
|
+
it_should_behave_like 'a rack env accessor' do
|
8
|
+
|
9
|
+
let(:object) { described_class.new(env) }
|
10
|
+
let(:rack_key) { 'REQUEST_METHOD' }
|
11
|
+
let(:rack_key_value) { method.verb }
|
12
|
+
let(:expected_value) { method }
|
13
|
+
|
14
|
+
#let(:expected_method)
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: request
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Markus Schirp
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: backports
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
- - ! '>='
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 3.0.3
|
25
|
+
type: :runtime
|
26
|
+
prerelease: false
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.0'
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 3.0.3
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: concord
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.1.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ~>
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 0.1.0
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: ice_nine
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 0.7.0
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.7.0
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: adamantium
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.0.7
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ~>
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 0.0.7
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: equalizer
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: 0.0.5
|
92
|
+
type: :runtime
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ~>
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 0.0.5
|
100
|
+
- !ruby/object:Gem::Dependency
|
101
|
+
name: abstract_type
|
102
|
+
requirement: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ~>
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: 0.0.5
|
108
|
+
type: :runtime
|
109
|
+
prerelease: false
|
110
|
+
version_requirements: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ~>
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 0.0.5
|
116
|
+
description: HTTP request porofication
|
117
|
+
email:
|
118
|
+
- mbj@seonic.net
|
119
|
+
executables: []
|
120
|
+
extensions: []
|
121
|
+
extra_rdoc_files:
|
122
|
+
- LICENSE
|
123
|
+
- README.md
|
124
|
+
- TODO
|
125
|
+
files:
|
126
|
+
- .gitignore
|
127
|
+
- .rspec
|
128
|
+
- .travis.yml
|
129
|
+
- Changelog.md
|
130
|
+
- Gemfile
|
131
|
+
- Gemfile.devtools
|
132
|
+
- Guardfile
|
133
|
+
- LICENSE
|
134
|
+
- README.md
|
135
|
+
- Rakefile
|
136
|
+
- TODO
|
137
|
+
- config/devtools.yml
|
138
|
+
- config/flay.yml
|
139
|
+
- config/flog.yml
|
140
|
+
- config/mutant.yml
|
141
|
+
- config/reek.yml
|
142
|
+
- config/roodi.yml
|
143
|
+
- config/yardstick.yml
|
144
|
+
- lib/request.rb
|
145
|
+
- lib/request/key.rb
|
146
|
+
- lib/request/method.rb
|
147
|
+
- lib/request/protocol.rb
|
148
|
+
- lib/request/rack.rb
|
149
|
+
- lib/request/routed.rb
|
150
|
+
- request.gemspec
|
151
|
+
- spec/shared/rack_env_accessor_behavior.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
- spec/unit/request/key/hash_spec.rb
|
154
|
+
- spec/unit/request/rack/host_spec.rb
|
155
|
+
- spec/unit/request/rack/if_modified_since_spec.rb
|
156
|
+
- spec/unit/request/rack/path_info_spec.rb
|
157
|
+
- spec/unit/request/rack/port_spec.rb
|
158
|
+
- spec/unit/request/rack/protocol_spec.rb
|
159
|
+
- spec/unit/request/rack/query_string_spec.rb
|
160
|
+
- spec/unit/request/rack/request_method_spec.rb
|
161
|
+
homepage: https://github.com/mbj/response
|
162
|
+
licenses: []
|
163
|
+
post_install_message:
|
164
|
+
rdoc_options: []
|
165
|
+
require_paths:
|
166
|
+
- lib
|
167
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
168
|
+
none: false
|
169
|
+
requirements:
|
170
|
+
- - ! '>='
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
|
+
none: false
|
175
|
+
requirements:
|
176
|
+
- - ! '>='
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubyforge_project:
|
181
|
+
rubygems_version: 1.8.23
|
182
|
+
signing_key:
|
183
|
+
specification_version: 3
|
184
|
+
summary: HTTP request porofication
|
185
|
+
test_files: []
|
186
|
+
has_rdoc:
|