cp-sparrow 0.0.11
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 +7 -0
- data/.gitignore +23 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +66 -0
- data/Rakefile +32 -0
- data/lib/sparrow.rb +25 -0
- data/lib/sparrow/configuration.rb +36 -0
- data/lib/sparrow/core_ext/hash.rb +21 -0
- data/lib/sparrow/middleware.rb +99 -0
- data/lib/sparrow/path_normalizer.rb +10 -0
- data/lib/sparrow/railtie.rb +11 -0
- data/lib/sparrow/request_middleware.rb +11 -0
- data/lib/sparrow/response_middleware.rb +37 -0
- data/lib/sparrow/route_parser.rb +32 -0
- data/lib/sparrow/strategies/form_hash.rb +42 -0
- data/lib/sparrow/strategies/ignore.rb +42 -0
- data/lib/sparrow/strategies/json_format_strategies/array_strategy.rb +17 -0
- data/lib/sparrow/strategies/json_format_strategies/default_json_format_strategy.rb +17 -0
- data/lib/sparrow/strategies/json_format_strategies/json_format_strategy.rb +35 -0
- data/lib/sparrow/strategies/json_format_strategies/rack_body.rb +17 -0
- data/lib/sparrow/strategies/key_transformation/camelize_key.rb +27 -0
- data/lib/sparrow/strategies/key_transformation/key_normalizer.rb +9 -0
- data/lib/sparrow/strategies/key_transformation/underscore_key.rb +13 -0
- data/lib/sparrow/strategies/raw_input.rb +48 -0
- data/lib/sparrow/strategies/transform_params.rb +38 -0
- data/lib/sparrow/transformable.rb +76 -0
- data/lib/sparrow/version.rb +3 -0
- data/sparrow.gemspec +35 -0
- data/spec/integration/apps/rack_app/app.rb +28 -0
- data/spec/integration/apps/rack_app/config.ru +12 -0
- data/spec/integration/apps/rails_app/README.rdoc +261 -0
- data/spec/integration/apps/rails_app/Rakefile +7 -0
- data/spec/integration/apps/rails_app/app/assets/javascripts/application.js +15 -0
- data/spec/integration/apps/rails_app/app/assets/stylesheets/application.css +13 -0
- data/spec/integration/apps/rails_app/app/controllers/application_controller.rb +3 -0
- data/spec/integration/apps/rails_app/app/controllers/welcome_controller.rb +50 -0
- data/spec/integration/apps/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/integration/apps/rails_app/app/mailers/.gitkeep +0 -0
- data/spec/integration/apps/rails_app/app/models/.gitkeep +0 -0
- data/spec/integration/apps/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/integration/apps/rails_app/config.ru +4 -0
- data/spec/integration/apps/rails_app/config/application.rb +72 -0
- data/spec/integration/apps/rails_app/config/boot.rb +10 -0
- data/spec/integration/apps/rails_app/config/environment.rb +5 -0
- data/spec/integration/apps/rails_app/config/environments/development.rb +31 -0
- data/spec/integration/apps/rails_app/config/environments/production.rb +64 -0
- data/spec/integration/apps/rails_app/config/environments/test.rb +32 -0
- data/spec/integration/apps/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/integration/apps/rails_app/config/initializers/inflections.rb +15 -0
- data/spec/integration/apps/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/integration/apps/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/integration/apps/rails_app/config/initializers/session_store.rb +8 -0
- data/spec/integration/apps/rails_app/config/initializers/wrap_parameters.rb +10 -0
- data/spec/integration/apps/rails_app/config/locales/en.yml +5 -0
- data/spec/integration/apps/rails_app/config/routes.rb +64 -0
- data/spec/integration/apps/rails_app/lib/assets/.gitkeep +0 -0
- data/spec/integration/apps/rails_app/public/404.html +26 -0
- data/spec/integration/apps/rails_app/public/422.html +26 -0
- data/spec/integration/apps/rails_app/public/500.html +25 -0
- data/spec/integration/apps/rails_app/public/favicon.ico +0 -0
- data/spec/integration/apps/rails_app/script/rails +6 -0
- data/spec/integration/rack/camel_caser_spec.rb +49 -0
- data/spec/integration/rails/camel_caser_accept_header_spec.rb +55 -0
- data/spec/integration/rails/camel_caser_spec.rb +207 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/rack_app_helper.rb +19 -0
- data/spec/support/rails_app_helper.rb +21 -0
- data/spec/support/unit_spec_helper.rb +5 -0
- data/spec/unit/camel_caser_spec.rb +23 -0
- data/spec/unit/camelize_key_spec.rb +19 -0
- data/spec/unit/configuration_spec.rb +47 -0
- data/spec/unit/path_normalizer_spec.rb +23 -0
- data/spec/unit/route_parser_spec.rb +45 -0
- metadata +295 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
require 'sparrow/transformable'
|
3
|
+
|
4
|
+
module Sparrow
|
5
|
+
module Strategies
|
6
|
+
class FormHash
|
7
|
+
REQUEST_FORM_HASH_KEY = 'rack.request.form_hash'
|
8
|
+
include Transformable
|
9
|
+
|
10
|
+
attr_reader :env, :type
|
11
|
+
|
12
|
+
def self.handle(env, type)
|
13
|
+
self.new(env, type).handle
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(env, type = :request, params = nil)
|
17
|
+
@env = env
|
18
|
+
@params = params
|
19
|
+
@type = type
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle
|
23
|
+
super
|
24
|
+
handle_form_hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def params
|
28
|
+
@params || env[REQUEST_FORM_HASH_KEY]
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def handle_form_hash
|
34
|
+
if params.present?
|
35
|
+
transformed_params = transform_params
|
36
|
+
@env[REQUEST_FORM_HASH_KEY] = transformed_params
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Sparrow
|
2
|
+
module Strategies
|
3
|
+
class Ignore
|
4
|
+
include Transformable
|
5
|
+
|
6
|
+
def initialize(env, type = :request, params = nil)
|
7
|
+
@env = env
|
8
|
+
@params = params
|
9
|
+
@type = type
|
10
|
+
end
|
11
|
+
|
12
|
+
def params
|
13
|
+
ret = @params || @env['rack.input'].send(:read)
|
14
|
+
@env['rack.input'].rewind
|
15
|
+
ret
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.handle(env, type)
|
19
|
+
new(env, type).handle
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle
|
23
|
+
# synchronize rack.input and form hash values
|
24
|
+
input = @env['rack.input'].gets
|
25
|
+
|
26
|
+
begin
|
27
|
+
@env['rack.request.form_hash'] = MultiJson.load(input)
|
28
|
+
rescue MultiJson::ParseError
|
29
|
+
# ignore
|
30
|
+
ensure
|
31
|
+
@env['rack.input'].rewind
|
32
|
+
end if input.present?
|
33
|
+
|
34
|
+
@env
|
35
|
+
end
|
36
|
+
|
37
|
+
def transform_params
|
38
|
+
ensure_json
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'sparrow/strategies/json_format_strategies/json_format_strategy'
|
2
|
+
|
3
|
+
module Sparrow
|
4
|
+
module Strategies
|
5
|
+
class ArrayStrategy < JsonFormatStrategy
|
6
|
+
register_json_format
|
7
|
+
|
8
|
+
def match?(input)
|
9
|
+
input.is_a? Array
|
10
|
+
end
|
11
|
+
|
12
|
+
def convert(input)
|
13
|
+
input.first
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'sparrow/strategies/json_format_strategies/default_json_format_strategy'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
|
4
|
+
module Sparrow
|
5
|
+
module Strategies
|
6
|
+
class JsonFormatStrategy
|
7
|
+
def initialize(*args)
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.register_json_format(*args)
|
12
|
+
init(args)
|
13
|
+
@@json_format_strategies << self.new(args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.convert(body)
|
17
|
+
strategy = json_format_strategies.select do |strategy|
|
18
|
+
strategy.match?(body)
|
19
|
+
end.first
|
20
|
+
strategy.convert(body)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def self.init(*args)
|
25
|
+
@@json_format_strategies ||= Array.new(args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.json_format_strategies
|
29
|
+
init
|
30
|
+
default = Sparrow::Strategies::DefaultJsonFormatStrategy.instance
|
31
|
+
@@json_format_strategies.reject(&:blank?) + [default]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/json_format_strategy'
|
2
|
+
|
3
|
+
module Sparrow
|
4
|
+
module Strategies
|
5
|
+
class RackBody < JsonFormatStrategy
|
6
|
+
register_json_format
|
7
|
+
|
8
|
+
def match?(input)
|
9
|
+
input.respond_to?(:body)
|
10
|
+
end
|
11
|
+
|
12
|
+
def convert(input)
|
13
|
+
input.body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/key_normalizer'
|
2
|
+
|
3
|
+
module Sparrow
|
4
|
+
module Strategies
|
5
|
+
class CamelizeKey
|
6
|
+
include KeyNormalizer
|
7
|
+
|
8
|
+
attr_accessor :strategy
|
9
|
+
|
10
|
+
def initialize(strategy = :lower)
|
11
|
+
self.strategy = strategy
|
12
|
+
end
|
13
|
+
|
14
|
+
def transform_key(key)
|
15
|
+
# dont touch all_Upper Keys (like "DE")
|
16
|
+
# unless configuration.default_ignore_all_uppercase_keys
|
17
|
+
# is set to false
|
18
|
+
if Sparrow.configuration.camelize_ignore_uppercase_keys &&
|
19
|
+
key.upcase == key
|
20
|
+
normalize_key(key)
|
21
|
+
else
|
22
|
+
normalize_key(key).camelize(strategy)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
|
3
|
+
module Sparrow
|
4
|
+
module Strategies
|
5
|
+
class RawInput
|
6
|
+
include Transformable
|
7
|
+
|
8
|
+
attr_reader :env, :type
|
9
|
+
|
10
|
+
def self.handle(env, type)
|
11
|
+
self.new(env, type).handle
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(env, type = :request, params = nil)
|
15
|
+
@env = env || {}
|
16
|
+
@params = params
|
17
|
+
@type = type
|
18
|
+
end
|
19
|
+
|
20
|
+
def handle
|
21
|
+
super
|
22
|
+
handle_raw_rack
|
23
|
+
end
|
24
|
+
|
25
|
+
def params
|
26
|
+
if @params
|
27
|
+
@params
|
28
|
+
else
|
29
|
+
input_io = @env['rack.input']
|
30
|
+
params = input_io.send(:read)
|
31
|
+
input_io.rewind
|
32
|
+
params
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def handle_raw_rack
|
39
|
+
if params.present?
|
40
|
+
new_raw_input = json_body.force_encoding("BINARY")
|
41
|
+
@env['rack.input'] = StringIO.new(new_raw_input)
|
42
|
+
@env['rack.input'].rewind
|
43
|
+
@env['CONTENT_LENGTH'] = new_raw_input.length
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'active_support/core_ext/string'
|
2
|
+
if ActiveSupport::VERSION::STRING.match(/3\.\d+\.\d+/)
|
3
|
+
require 'sparrow/core_ext/hash'
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'sparrow/strategies/key_transformation/underscore_key'
|
7
|
+
require 'sparrow/strategies/key_transformation/camelize_key'
|
8
|
+
|
9
|
+
module Sparrow
|
10
|
+
module Strategies
|
11
|
+
class TransformParams
|
12
|
+
attr_accessor :key_transformation_strategy
|
13
|
+
|
14
|
+
def initialize(key_transformation_strategy_buzzword)
|
15
|
+
key_transformation_strategy = create_key_transformation_strategy(
|
16
|
+
key_transformation_strategy_buzzword)
|
17
|
+
self.key_transformation_strategy = key_transformation_strategy
|
18
|
+
end
|
19
|
+
|
20
|
+
def transform(collection_or_hash)
|
21
|
+
case collection_or_hash
|
22
|
+
when Array
|
23
|
+
collection_or_hash.map { |element| transform(element) }
|
24
|
+
when Hash
|
25
|
+
collection_or_hash.deep_transform_keys do |key|
|
26
|
+
key_transformation_strategy.transform_key(key)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_key_transformation_strategy(key_transformation_strategy_buzzword)
|
32
|
+
class_name = "#{key_transformation_strategy_buzzword.to_s}_key".camelize
|
33
|
+
strategy_class = "Sparrow::Strategies::#{class_name}".constantize
|
34
|
+
strategy_class.new
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'sparrow/strategies/transform_params'
|
2
|
+
require 'sparrow/strategies/json_format_strategies/json_format_strategy'
|
3
|
+
|
4
|
+
if ActiveSupport::VERSION::STRING.match(/3\.\d+\.\d+/)
|
5
|
+
require 'active_support/core_ext/object/to_param'
|
6
|
+
require 'active_support/core_ext/object/to_query'
|
7
|
+
end
|
8
|
+
|
9
|
+
module Sparrow
|
10
|
+
module Transformable
|
11
|
+
def transform_params
|
12
|
+
transform_params_strategy.transform(ensure_json)
|
13
|
+
end
|
14
|
+
|
15
|
+
def transform_strategy
|
16
|
+
default =
|
17
|
+
Sparrow.configuration.default_json_key_transformation_strategy(type)
|
18
|
+
strategy = json_format || default
|
19
|
+
strategy.to_sym
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle
|
23
|
+
transform_query_string
|
24
|
+
end
|
25
|
+
|
26
|
+
def json_body
|
27
|
+
json = parsable_json_string(transform_params)
|
28
|
+
MultiJson.load(json)
|
29
|
+
json
|
30
|
+
rescue MultiJson::ParseError
|
31
|
+
MultiJson.dump(ensure_json)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def json_format
|
36
|
+
if respond_to?(:env) then
|
37
|
+
env[Sparrow.configuration.json_format_header(type)]
|
38
|
+
else
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def ensure_json
|
44
|
+
json_params = if !params.is_a?(Hash)
|
45
|
+
Sparrow::Strategies::JsonFormatStrategy.convert(params)
|
46
|
+
elsif params.is_a?(Hash) && params.values == [nil] &&
|
47
|
+
params.keys.length == 1
|
48
|
+
params.keys.first
|
49
|
+
else
|
50
|
+
params
|
51
|
+
end
|
52
|
+
return MultiJson.load(json_params) if json_params.is_a?(String)
|
53
|
+
json_params
|
54
|
+
end
|
55
|
+
|
56
|
+
def parsable_json_string(transformable_params)
|
57
|
+
if [Hash, Array].include? transformable_params.class
|
58
|
+
MultiJson.dump(transformable_params)
|
59
|
+
else
|
60
|
+
transformable_params
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def transform_params_strategy
|
65
|
+
transform_params = Sparrow::Strategies::TransformParams
|
66
|
+
transform_params.new(transform_strategy)
|
67
|
+
end
|
68
|
+
|
69
|
+
def transform_query_string
|
70
|
+
env_query_hash = Rack::Utils.parse_nested_query(env['QUERY_STRING'])
|
71
|
+
transformed_hash = transform_params_strategy.transform(env_query_hash)
|
72
|
+
env['QUERY_STRING'] = transformed_hash.to_param
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/sparrow.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
rails_version = ENV["RAILS_VERSION"] || "3.2.21"
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'sparrow/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "cp-sparrow"
|
9
|
+
spec.version = Sparrow::VERSION
|
10
|
+
spec.authors = ["Daniel Schmidt", "Andreas Müller"]
|
11
|
+
spec.email = ["dsci@code79.net", "anmuel86@gmail.com"]
|
12
|
+
spec.summary = %q{A POC to have a Rack middleware parsing the params keys into underscore}
|
13
|
+
spec.description = %q{
|
14
|
+
A collection of 2 middlewares to convert json formats to other formats
|
15
|
+
such as camelCase and snake_case. Both converting responses and requests are
|
16
|
+
supported.
|
17
|
+
}
|
18
|
+
spec.homepage = ""
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.files = `git ls-files -z`.split("\x0")
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_runtime_dependency "activesupport", ">= 3.2.17"
|
27
|
+
spec.add_development_dependency "pry"
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
29
|
+
spec.add_development_dependency "rake"
|
30
|
+
spec.add_development_dependency "rspec", '~> 3'
|
31
|
+
spec.add_development_dependency "rspec-its"
|
32
|
+
spec.add_development_dependency "rack-test"
|
33
|
+
spec.add_development_dependency "multi_json"
|
34
|
+
spec.add_development_dependency "rails", rails_version
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class App
|
2
|
+
|
3
|
+
def call(env)
|
4
|
+
params = env["rack.input"].gets
|
5
|
+
response = Rack::Response.new
|
6
|
+
response['Content-Type'] = 'application/json'
|
7
|
+
response.write(json_response(params))
|
8
|
+
response.finish
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def json_response(params)
|
14
|
+
hsh_params = MultiJson.load(params)
|
15
|
+
keys = hsh_params.reduce([]) do |result, (key, value)|
|
16
|
+
result << key
|
17
|
+
if value.is_a?(Hash)
|
18
|
+
result << value.keys
|
19
|
+
end
|
20
|
+
result
|
21
|
+
end.flatten
|
22
|
+
MultiJson.dump({
|
23
|
+
keys: keys,
|
24
|
+
fakeKey: true,
|
25
|
+
fake_key: false
|
26
|
+
})
|
27
|
+
end
|
28
|
+
end
|