Skip to content

Removes dependency on Hashie::Mash #1279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ post 'users/signup' do
end
````

If we do not specify any params, `declared` will return an empty `Hashie::Mash` instance.
If we do not specify any params, `declared` will return an empty `Hash` instance.

**Request**

Expand Down Expand Up @@ -545,13 +545,6 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d
}
````

The returned hash is a `Hashie::Mash` instance, allowing you to access parameters via dot notation:

```ruby
declared(params).user == declared(params)['user']
```


The `#declared` method is not available to `before` filters, as those are evaluated prior
to parameter coercion.

Expand Down Expand Up @@ -866,10 +859,10 @@ params do
requires :avatar, type: File
end
post '/' do
# Parameter will be wrapped using Hashie:
params.avatar.filename # => 'avatar.png'
params.avatar.type # => 'image/png'
params.avatar.tempfile # => #<File>
# Parameter will be a plain Hash:
params[:avatar][:filename] # => 'avatar.png'
params[:avatar][:type] # => 'image/png'
params[:avatar][:tempfile] # => #<File>
end
```

Expand Down
1 change: 0 additions & 1 deletion grape.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ Gem::Specification.new do |s|
s.add_runtime_dependency 'activesupport'
s.add_runtime_dependency 'multi_json', '>= 1.3.2'
s.add_runtime_dependency 'multi_xml', '>= 0.5.2'
s.add_runtime_dependency 'hashie', '>= 2.1.0'
s.add_runtime_dependency 'virtus', '>= 1.0.0'
s.add_runtime_dependency 'builder'

Expand Down
3 changes: 2 additions & 1 deletion lib/grape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
require 'rack/accept'
require 'rack/auth/basic'
require 'rack/auth/digest/md5'
require 'hashie'
require 'set'
require 'active_support/version'
require 'active_support/core_ext/hash/indifferent_access'
Expand All @@ -15,8 +14,10 @@
require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/conversions'
require 'active_support/core_ext/hash/keys'
require 'active_support/dependencies/autoload'
require 'active_support/notifications'
require 'grape/core_ext/hash'
require 'multi_json'
require 'multi_xml'
require 'i18n'
Expand Down
49 changes: 49 additions & 0 deletions lib/grape/core_ext/hash.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
class Hash
def deep_symbolize_keys
_deep_transform_keys_in_object(self) do |key|
begin
key.to_sym
rescue
key
end
end
end unless Hash.method_defined?(:deep_symbolize_keys)

def deep_symbolize_keys!
_deep_transform_keys_in_object!(self) do |key|
begin
key.to_sym
rescue
key
end
end
end unless Hash.method_defined?(:deep_symbolize_keys!)

def _deep_transform_keys_in_object(object, &block)
case object
when Hash
object.each_with_object({}) do |(key, value), result|
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
end
when Array
object.map { |e| _deep_transform_keys_in_object(e, &block) }
else
object
end
end unless Hash.method_defined?(:_deep_transform_keys_in_object)

def _deep_transform_keys_in_object!(object, &block)
case object
when Hash
object.keys.each do |key|
value = object.delete(key)
object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
end
object
when Array
object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
else
object
end
end unless Hash.method_defined?(:_deep_transform_keys_in_object!)
end
2 changes: 1 addition & 1 deletion lib/grape/dsl/inside_route.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def declared(params, options = {}, declared_params = nil)
declared(param || {}, options, declared_params)
end
else
declared_params.each_with_object(Hashie::Mash.new) do |key, hash|
declared_params.each_with_object({}) do |key, hash|
key = { key => nil } unless key.is_a? Hash

key.each_pair do |parent, children|
Expand Down
4 changes: 2 additions & 2 deletions lib/grape/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ def headers
private

def build_params
params = Hashie::Mash.new(rack_params)
params = Hash[rack_params]
if env[Grape::Env::GRAPE_ROUTING_ARGS]
args = env[Grape::Env::GRAPE_ROUTING_ARGS].dup
# preserve version from query string parameters
args.delete(:version)
args.delete(:route_info)
params.deep_merge!(args)
end
params
params.deep_symbolize_keys
end

def build_headers
Expand Down
6 changes: 3 additions & 3 deletions lib/grape/validations/types/custom_type_coercer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def infer_type_check(type)
# Enforce symbolized keys for complex types
# by wrapping the coercion method such that
# any Hash objects in the immediate heirarchy
# are passed through +Hashie.symbolize_keys!+.
# have their keys recursively symbolized
# This helps common libs such as JSON to work easily.
#
# @param type see #new
Expand All @@ -162,15 +162,15 @@ def enforce_symbolized_keys(type, method)
lambda do |val|
method.call(val).tap do |new_value|
new_value.each do |item|
Hashie.symbolize_keys!(item) if item.is_a? Hash
item.deep_symbolize_keys! if item.is_a? Hash
end
end
end

# Hash objects are processed directly
elsif type == Hash
lambda do |val|
Hashie.symbolize_keys! method.call(val)
method.call(val).deep_symbolize_keys!
end

# Simple types are not processed.
Expand Down
5 changes: 2 additions & 3 deletions lib/grape/validations/types/file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ def coerce(input)

def value_coerced?(value)
# Rack::Request creates a Hash with filename,
# content type and an IO object. Grape wraps that
# using hashie for convenience. Do a bit of basic
# content type and an IO object. Do a bit of basic
# duck-typing.
value.is_a?(Hashie::Mash) && value.key?(:tempfile)
value.respond_to?(:key?) && value.key?(:tempfile)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/grape/endpoint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ def app
optional :fifth, default: nil
requires :nested_nested, type: Hash do
optional :sixth, default: 'sixth-default'
optional :seven, default: nil
optional :seventh, default: nil
end
end
end
Expand All @@ -456,9 +456,9 @@ def app

expect(last_response.status).to eq(200)
expect(inner_params[:first]).to eq 'present'
expect(inner_params[:nested].keys).to eq %w(fourth fifth nested_nested)
expect(inner_params[:nested].keys).to eq [:fourth, :fifth, :nested_nested]
expect(inner_params[:nested][:fourth]).to eq ''
expect(inner_params[:nested][:nested_nested].keys).to eq %w(sixth seven)
expect(inner_params[:nested][:nested_nested].keys).to eq [:sixth, :seventh]
expect(inner_params[:nested][:nested_nested][:sixth]).to eq 'sixth'
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/grape/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module Grape
end

it 'returns params' do
expect(request.params).to eq('a' => '123', 'b' => 'xyz')
expect(request.params).to eq(a: '123', b: 'xyz')
end

describe 'with grape.routing_args' do
Expand All @@ -47,7 +47,7 @@ module Grape
end

it 'cuts version and route_info' do
expect(request.params).to eq('a' => '123', 'b' => 'xyz', 'c' => 'ccc')
expect(request.params).to eq(a: '123', b: 'xyz', c: 'ccc')
end
end
end
Expand Down
1 change: 1 addition & 0 deletions spec/grape/validations/params_scope_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ def initialize(value)
requires :b
end
end
subject.before_validation { p params }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug code leftover ...

subject.get('/group') { 'group works' }
get '/group', a: [{ b: true }]
expect(last_response.status).to eq(200)
Expand Down
4 changes: 2 additions & 2 deletions spec/grape/validations/validators/coerce_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ class User
requires :file, type: Rack::Multipart::UploadedFile
end
subject.post '/upload' do
params[:file].filename
params[:file][:filename]
end

post '/upload', file: Rack::Test::UploadedFile.new(__FILE__)
Expand All @@ -302,7 +302,7 @@ class User
requires :file, coerce: File
end
subject.post '/upload' do
params[:file].filename
params[:file][:filename]
end

post '/upload', file: Rack::Test::UploadedFile.new(__FILE__)
Expand Down