cp-sparrow 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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
|