cp-sparrow 0.0.12 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.ruby-version +1 -1
  4. data/LICENSE.txt +1 -1
  5. data/README.md +96 -13
  6. data/lib/sparrow.rb +21 -4
  7. data/lib/sparrow/configuration.rb +23 -2
  8. data/lib/sparrow/core_ext/hash.rb +2 -0
  9. data/lib/sparrow/dependencies.rb +15 -0
  10. data/lib/sparrow/http_message.rb +103 -0
  11. data/lib/sparrow/logger.rb +53 -0
  12. data/lib/sparrow/middleware.rb +44 -63
  13. data/lib/sparrow/request_http_message.rb +22 -0
  14. data/lib/sparrow/request_middleware.rb +8 -10
  15. data/lib/sparrow/response_http_message.rb +49 -0
  16. data/lib/sparrow/response_middleware.rb +32 -28
  17. data/lib/sparrow/response_steward.rb +13 -0
  18. data/lib/sparrow/route_parser.rb +28 -5
  19. data/lib/sparrow/steward.rb +125 -0
  20. data/lib/sparrow/strategies.rb +6 -0
  21. data/lib/sparrow/strategies/form_hash.rb +27 -11
  22. data/lib/sparrow/strategies/ignore.rb +33 -5
  23. data/lib/sparrow/strategies/json_format_strategies.rb +4 -0
  24. data/lib/sparrow/strategies/json_format_strategies/array_json_format_strategy.rb +23 -0
  25. data/lib/sparrow/strategies/json_format_strategies/default_json_format_strategy.rb +11 -2
  26. data/lib/sparrow/strategies/json_format_strategies/json_format_strategy.rb +21 -6
  27. data/lib/sparrow/strategies/json_format_strategies/rack_body_json_format_strategy.rb +22 -0
  28. data/lib/sparrow/strategies/key_transformation.rb +2 -0
  29. data/lib/sparrow/strategies/key_transformation/camelize_key.rb +45 -17
  30. data/lib/sparrow/strategies/key_transformation/underscore_key.rb +17 -6
  31. data/lib/sparrow/strategies/raw_input.rb +29 -7
  32. data/lib/sparrow/strategies/transform_params.rb +46 -21
  33. data/lib/sparrow/transformable.rb +28 -20
  34. data/lib/sparrow/version.rb +1 -1
  35. data/sparrow.gemspec +1 -1
  36. data/spec/integration/apps/rails_app/config/boot.rb +1 -1
  37. data/spec/integration/rack/camel_caser_spec.rb +2 -2
  38. data/spec/unit/camelize_key_spec.rb +9 -7
  39. data/spec/unit/configuration_spec.rb +3 -0
  40. data/spec/unit/http_message.rb +66 -0
  41. data/spec/unit/logger_spec.rb +6 -0
  42. data/spec/unit/{camel_caser_spec.rb → sparrow_spec.rb} +8 -2
  43. data/spec/unit/steward_spec.rb +31 -0
  44. metadata +24 -13
  45. data/lib/sparrow/path_normalizer.rb +0 -10
  46. data/lib/sparrow/strategies/json_format_strategies/array_strategy.rb +0 -17
  47. data/lib/sparrow/strategies/json_format_strategies/rack_body.rb +0 -17
  48. data/lib/sparrow/strategies/key_transformation/key_normalizer.rb +0 -9
  49. data/spec/unit/path_normalizer_spec.rb +0 -23
@@ -1,17 +1,33 @@
1
1
  module Sparrow
2
2
  module Strategies
3
+ ##
4
+ # This strategy is called when the HTTP message shall +not+ be transformed,
5
+ # i.e. ignored.
6
+ # This is inspired by the NullObject-Pattern to be convenient.
3
7
  class Ignore
4
8
  include Transformable
5
9
 
10
+ ##
11
+ # Create a new IgnoreStrategy
12
+ # @param [Hash] env the Rack environment
13
+ # @param [Symbol] type HTTP message type. Must be either :request or
14
+ # :response
15
+ # @param [Hash] params The HTTP message params if not given in the env
6
16
  def initialize(env, type = :request, params = nil)
7
17
  @env = env
8
18
  @params = params
9
19
  @type = type
10
20
  end
11
21
 
22
+ ##
23
+ # Although we are ignoring any kind of conversion we still need to read
24
+ # the parameters from the environment to be convenient with all other
25
+ # calls in the chains and architecture *sigh*
26
+ # Checks env['rack.input']
27
+ # @return [Hash] the params
12
28
  def params
13
- ret = @params || @env['rack.input'].send(:read)
14
- @env['rack.input'].rewind
29
+ ret = @params || @env[HttpMessage::RACK_INPUT_KEY].send(:read)
30
+ @env[HttpMessage::RACK_INPUT_KEY].rewind
15
31
  ret
16
32
  end
17
33
 
@@ -19,25 +35,37 @@ module Sparrow
19
35
  new(env, type).handle
20
36
  end
21
37
 
38
+ ##
39
+ # handles the conversion, i.e. here "do nothing"
40
+ # Which is not strictly true - at write the rack.input to the form hash
41
+ # key for convenience reasons to enable further middlewares to work with
42
+ # it
43
+ # @return [Hash] the rack env
22
44
  def handle
23
45
  # synchronize rack.input and form hash values
24
- input = @env['rack.input'].gets
46
+ input = @env[HttpMessage::RACK_INPUT_KEY].gets
25
47
 
26
48
  begin
27
- @env['rack.request.form_hash'] = MultiJson.load(input)
49
+ @env[HttpMessage::FORM_HASH_KEY] = MultiJson.load(input)
28
50
  rescue MultiJson::ParseError
29
51
  # ignore
30
52
  ensure
31
- @env['rack.input'].rewind
53
+ @env[HttpMessage::RACK_INPUT_KEY].rewind
32
54
  end if input.present?
33
55
 
34
56
  @env
35
57
  end
36
58
 
59
+ ##
60
+ # Alias for #params
61
+ # @see #params
37
62
  def json_body
38
63
  params
39
64
  end
40
65
 
66
+ ##
67
+ # Transforms the params to a Ruby JSON Hash representation
68
+ # @return [Hash] the JSON
41
69
  def transform_params
42
70
  ensure_json
43
71
  end
@@ -0,0 +1,4 @@
1
+ require 'sparrow/strategies/json_format_strategies/default_json_format_strategy'
2
+ require 'sparrow/strategies/json_format_strategies/json_format_strategy'
3
+ require 'sparrow/strategies/json_format_strategies/array_json_format_strategy'
4
+ require 'sparrow/strategies/json_format_strategies/rack_body_json_format_strategy'
@@ -0,0 +1,23 @@
1
+ module Sparrow
2
+ module Strategies
3
+ class ArrayJsonFormatStrategy < JsonFormatStrategy
4
+ register_json_format
5
+
6
+ ##
7
+ # Matches if input is an Array
8
+ # @param [Object] input the JSON object
9
+ # @return true if the input is an Array
10
+ def match?(input)
11
+ input.is_a? Array
12
+ end
13
+
14
+ ##
15
+ # Takes the first element from the Array and returns it
16
+ # @param [Array] input the input Array
17
+ # @return [String] the first element of the input as a String
18
+ def convert(input)
19
+ input.first.to_s
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,14 +1,23 @@
1
- require 'singleton'
2
-
3
1
  module Sparrow
4
2
  module Strategies
3
+ ##
4
+ # NullObject JSON Format Strategy
5
+ # Does no direct conversion except casting the given object to a string
5
6
  class DefaultJsonFormatStrategy
6
7
  include Singleton
7
8
 
9
+ ##
10
+ # Matches always since this is the NullObjectStrategy and thus the
11
+ # fallback.
12
+ # @param [Object] input the JSON input
13
+ # @return [Boolean] True
8
14
  def match?(input)
9
15
  true
10
16
  end
11
17
 
18
+ ##
19
+ # @param [#to_s] input the JSON object
20
+ # @return [String] the input as a String
12
21
  def convert(input)
13
22
  input.to_s
14
23
  end
@@ -1,22 +1,37 @@
1
- require 'sparrow/strategies/json_format_strategies/default_json_format_strategy'
2
- require 'active_support/core_ext/object/blank'
3
-
4
1
  module Sparrow
5
2
  module Strategies
3
+ ##
4
+ # Superclass for all JSON format strategies.
5
+ # Contains no own instance logic, but keeps track of the registration
6
+ # of all JSON format strategies with its Singleton class methods.
7
+ # @abstract Not exactly a abstract class but contains no own logic but
8
+ # singleton class methods
6
9
  class JsonFormatStrategy
10
+ ##
11
+ # Empty constructor. Does nothing.
7
12
  def initialize(*args)
8
-
9
13
  end
10
14
 
15
+ ##
16
+ # Register a new JSON Format strategy
17
+ # @param [Object] args the arguments for the new strategy
18
+ # @return [Array] args the updated registered JSON Format strategies
19
+ # available
11
20
  def self.register_json_format(*args)
12
21
  init(args)
13
22
  @@json_format_strategies << self.new(args)
14
23
  end
15
24
 
25
+ ##
26
+ # Start a JSON conversion by its given string
27
+ # @param [Object] body a JSON object representation.
28
+ # can be any type a JSON format strategy is registered,
29
+ # i.e. an Array, a String or a RackBody
30
+ # @return [String] the formatted JSON
16
31
  def self.convert(body)
17
- strategy = json_format_strategies.select do |strategy|
32
+ strategy = json_format_strategies.detect do |strategy|
18
33
  strategy.match?(body)
19
- end.first
34
+ end
20
35
  strategy.convert(body)
21
36
  end
22
37
 
@@ -0,0 +1,22 @@
1
+ module Sparrow
2
+ module Strategies
3
+ class RackBodyJsonFormatStrategy < JsonFormatStrategy
4
+ register_json_format
5
+
6
+ ##
7
+ # Checks if the input is a RackBody
8
+ # @param [#body] input the possible JSON input object
9
+ # @return [Boolean] True if the given input responds to #body
10
+ def match?(input)
11
+ input.respond_to?(:body)
12
+ end
13
+
14
+ ##
15
+ # @param [#body] input the JSON input object
16
+ # @return [String] the input body
17
+ def convert(input)
18
+ input.body
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,2 @@
1
+ require 'sparrow/strategies/key_transformation/underscore_key'
2
+ require 'sparrow/strategies/key_transformation/camelize_key'
@@ -1,25 +1,53 @@
1
- require File.dirname(__FILE__) + '/key_normalizer'
2
-
3
1
  module Sparrow
4
2
  module Strategies
5
- class CamelizeKey
6
- include KeyNormalizer
3
+ module KeyTransformation
4
+ ##
5
+ # Strategy class for converting JSON to a camelized format.
6
+ # Meaning snake_case => snakeCase
7
+ class CamelizeKey
8
+ ##
9
+ # @return [Symbol] the camelizing strategy
10
+ # @see #initialize
11
+ attr_accessor :strategy
7
12
 
8
- attr_accessor :strategy
13
+ ##
14
+ # @return [Boolean] Defines whether complete uppercased keys will be
15
+ # transformed
16
+ # @see #initialize
17
+ attr_accessor :camelize_ignore_uppercase_keys
9
18
 
10
- def initialize(strategy = :lower)
11
- self.strategy = strategy
12
- end
19
+ ##
20
+ # Initialize a new CamelizeKey strategy
21
+ # @param [Hash] options camelize options
22
+ # @option options [Symbol] :strategy ('lower') defines the camelizing
23
+ # strategy type. Defines how to camelize, which comes down to starting
24
+ # with a lowercased character or with an uppercased character.
25
+ # Thus possible values are :lower and :upper.
26
+ #
27
+ # @option options [Boolean] :camelize_ignore_uppercase_keys (true)
28
+ # Defines if already completely uppercased keys should not be
29
+ # transformed. I.e. JSON stays JSON if
30
+ # this is set to true. If it is set to false JSON will be transformed
31
+ # to Json.
32
+ def initialize(options = {})
33
+ self.strategy = options.fetch(:strategy, :lower)
34
+ self.camelize_ignore_uppercase_keys =
35
+ options.fetch(:camelize_ignore_uppercase_keys, true)
36
+ end
13
37
 
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)
38
+ ##
39
+ # Transform the given key to camelCase based on the configuration
40
+ # options set on initialization.
41
+ # @see #initialize
42
+ # @param [String, #to_s] key the key value to be transformed
43
+ # @return [String] the transformed key
44
+ def transform_key(key)
45
+ key = key.to_s
46
+ if camelize_ignore_uppercase_keys && key.upcase == key
47
+ key
48
+ else
49
+ key.camelize(strategy)
50
+ end
23
51
  end
24
52
  end
25
53
  end
@@ -1,12 +1,23 @@
1
- require File.dirname(__FILE__) + '/key_normalizer'
2
-
3
1
  module Sparrow
4
2
  module Strategies
5
- class UnderscoreKey
6
- include KeyNormalizer
3
+ module KeyTransformation
4
+ ##
5
+ # Strategy class for snake_casing keys
6
+ class UnderscoreKey
7
+ ##
8
+ # Create a new UnderscoreKey Strategy
9
+ # Does nothing except returning a plain instance.
10
+ def initialize(*args)
11
+ # no initialization needed
12
+ end
7
13
 
8
- def transform_key(key)
9
- normalize_key(key).underscore
14
+ ##
15
+ # Transforms the given key to snake_case format
16
+ # @param [String] key the key to be transformed
17
+ # @return [String] the snake_cased key
18
+ def transform_key(key)
19
+ key.to_s.underscore
20
+ end
10
21
  end
11
22
  end
12
23
  end
@@ -1,32 +1,54 @@
1
- require 'active_support/core_ext/object/blank'
2
-
3
1
  module Sparrow
4
2
  module Strategies
3
+ ##
4
+ # Handles plain JSON input parameter conversion which is sent via
5
+ # env['rack.input']
5
6
  class RawInput
6
7
  include Transformable
7
8
 
8
- attr_reader :env, :type
9
+ # @return [Hash] the Rack environment
10
+ # @see #initialize
11
+ attr_reader :env
12
+ # @return [Symbol] the HTTP message type
13
+ # @see #initialize
14
+ attr_reader :type
9
15
 
16
+ ##
17
+ # Do the transformation
18
+ # @return [Hash] the converted JSON as a Hash representation
10
19
  def self.handle(env, type)
11
20
  self.new(env, type).handle
12
21
  end
13
22
 
23
+ # Create a new RawInput Strategy
24
+ # @param [Hash] env the Rack environment
25
+ # @param [Symbol] type the HTTP message type. Must be either :request or
26
+ # :response
27
+ # @param [Hash] params the HTTP message parameters to be transformed
28
+ # if not already present in the env
14
29
  def initialize(env, type = :request, params = nil)
15
30
  @env = env || {}
16
31
  @params = params
17
32
  @type = type
18
33
  end
19
34
 
35
+ ##
36
+ # Starts the conversion
37
+ # @return [Hash] the converted Rack environment
20
38
  def handle
21
39
  super
22
40
  handle_raw_rack
23
41
  end
24
42
 
43
+ ##
44
+ # The parameters to be transformed
45
+ # @return [Hash] the JSON parameters
46
+ # @see #initialize
25
47
  def params
26
48
  if @params
27
49
  @params
28
50
  else
29
- input_io = @env['rack.input']
51
+ input_io = @env[HttpMessage::RACK_INPUT_KEY]
30
52
  params = input_io.send(:read)
31
53
  input_io.rewind
32
54
  params
@@ -37,9 +59,9 @@ module Sparrow
37
59
 
38
60
  def handle_raw_rack
39
61
  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
62
+ new_raw_input = json_body.force_encoding("BINARY")
63
+ @env[HttpMessage::RACK_INPUT_KEY] = StringIO.new(new_raw_input)
64
+ @env[HttpMessage::RACK_INPUT_KEY].rewind
43
65
  @env['CONTENT_LENGTH'] = new_raw_input.length
44
66
  end
45
67
  end
@@ -1,37 +1,62 @@
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
1
  module Sparrow
10
2
  module Strategies
3
+ ##
4
+ # Core class to trigger the conversion
11
5
  class TransformParams
6
+ ##
7
+ # the strategy stating how to convert the JSON
8
+ # @return [KeyTransformation] key transformation strategy
9
+ # @see #initialize
12
10
  attr_accessor :key_transformation_strategy
13
11
 
14
- def initialize(key_transformation_strategy_buzzword)
15
- key_transformation_strategy = create_key_transformation_strategy(
16
- key_transformation_strategy_buzzword)
12
+ ##
13
+ # Key Transformation Strategy options. Possible values differ by
14
+ # the specific strategy. E.g. for CamelizeKey options may be
15
+ # the strategy and camlize_uppercase_params
16
+ # @see KeyTransformationStrategy::CamelizeKey
17
+ # @see KeyTransformationStrategy::UnderscoreKey
18
+ attr_accessor :options
19
+
20
+ ##
21
+ # Create a new TransformParams instance
22
+ # @param [String] key_transformation_strategy_buzzword the strategy
23
+ # buzzword stating how to transform. Must be either 'camelize' or
24
+ # 'underscore'
25
+ # @param [Hash] options options for the key transformation strategy
26
+ def initialize(key_transformation_strategy_buzzword, options = {})
27
+ self.options = options
28
+ key_transformation_strategy = create_key_transformation_strategy(
29
+ key_transformation_strategy_buzzword)
17
30
  self.key_transformation_strategy = key_transformation_strategy
18
31
  end
19
32
 
33
+ ##
34
+ # Do the transformation
35
+ # @param [Array|Hash] collection_or_hash the object to be transformed
36
+ # if it is an Array each object inside of it will be transformed, i.e.
37
+ # each Hash's keys
38
+ # if it is a Hash each key will be transformed. Recursively.
39
+ # @return [Array|Hash] the transformed input
20
40
  def transform(collection_or_hash)
21
41
  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
42
+ when Array
43
+ collection_or_hash.map { |element| transform(element) }
44
+ when Hash
45
+ collection_or_hash.deep_transform_keys do |key|
46
+ key_transformation_strategy.transform_key(key)
47
+ end
28
48
  end
29
49
  end
30
50
 
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
51
+ private
52
+
53
+ def create_key_transformation_strategy(key_transformation_strategy)
54
+ class_name = "#{key_transformation_strategy.to_s}_key"
55
+ class_name = class_name.camelize
56
+ full_strategy_class_name =
57
+ "Sparrow::Strategies::KeyTransformation::#{class_name}"
58
+ strategy_class = full_strategy_class_name.constantize
59
+ strategy_class.new(options)
35
60
  end
36
61
  end
37
62
  end