Skip to content
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

Replace hashie mash with hash #1594

Closed
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a908eb7
Ignore .ruby-version, .ruby-gemset and byebug_history.
Mar 10, 2017
1afdc91
replace Hashie::Mash with ActiveSupport::HashWithIndifferentAccess
msroot Oct 28, 2016
162f28c
Move hashie from gemspec to Gemfile Development dependency.
Mar 13, 2017
57f4545
Replace references to ActiveSupport::HashWithIndifferentAccess.
Mar 13, 2017
1787cb7
Deep symbolize module for converting a Hash.
Mar 12, 2017
71052c8
Create DeepMergeableHash.
Mar 16, 2017
790443b
Add parameter builder extensions.
Mar 16, 2017
d9e8ed0
Update coerce_spec for Hashie::Mash.
Mar 16, 2017
bbb88e3
Update endpoint_spec to test setting param builder.
Mar 16, 2017
eabe213
Update request_spec to expect a symbolized Hash.
Mar 16, 2017
2a21427
Add build_with to the parameters dsl to select the builder.
Mar 16, 2017
e54e2d0
Use build_with in Endpoint to pass to Grape::Request.
Mar 16, 2017
2201d15
Plug the parameter builder extensions into Grape::Request.
Mar 16, 2017
85e02c7
Ensure deep symbolization of coerced params in Hash's.
Mar 16, 2017
d7c1daa
Switch Grape::Request to use Hash as default.
Mar 16, 2017
2491071
Add build_parameters_with to Grape::Middleware::Globals
Mar 16, 2017
f4aeb9d
Update gemfiles from appraisal and exclude from Rubocop.
Mar 13, 2017
dc07f38
Change README.md to reference Hash not HashWithIndifferentAccess
Mar 16, 2017
6c2d614
Update CHANGELOG.md with PR 1594.
Mar 13, 2017
abae16c
Ensure CustomTypeCoercer works with plain Hash.
Apr 6, 2017
247869b
Switch the default params to HashWithIndifferentAccess.
Apr 6, 2017
6e5964b
Document the changes to params in README and UPGRADING.
Apr 6, 2017
2ddaa42
Some adjustments to README.md.
Apr 6, 2017
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ coverage
doc
pkg
.rvmrc
.ruby-version
.ruby-gemset
.bundle
.yardoc/*
.byebug_history
dist
Gemfile.lock
gemfiles/*.lock
Expand Down
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ AllCops:
TargetRubyVersion: 2.1
Include:
- Dangerfile
- gemfiles/*.gemfile

Exclude:
- vendor/**/*
- bin/**/*
- gemfiles/*.gemfile

inherit_from: .rubocop_todo.yml

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#### Features

* [#1594](https://github.com/ruby-grape/grape/pull/1594): Make Hashie::Mash params optional - [@james2m](https://github.com/james2m).
* [#1555](https://github.com/ruby-grape/grape/pull/1555): Added code coverage w/Coveralls - [@dblock](https://github.com/dblock).
* [#1568](https://github.com/ruby-grape/grape/pull/1568): Add `proc` option to `values` validator to allow custom checks - [@jlfaber](https://github.com/jlfaber).
* [#1575](https://github.com/ruby-grape/grape/pull/1575): Include nil values for missing nested params in declared - [@thogg4](https://github.com/thogg4).
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ group :development, :test do
gem 'bundler'
gem 'rake'
gem 'rubocop', '0.47.0'
gem 'hashie', require: false
end

group :development do
Expand Down
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,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 `ActiveSupport::HashWithIndifferentAccess` hash.

**Request**

Expand Down Expand Up @@ -562,10 +562,10 @@ 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:
The returned hash is a `ActiveSupport::HashWithIndifferentAccess` hash.

```ruby
declared(params).user == declared(params)['user']
declared(params)[:user] == declared(params)['user']
Copy link
Member

Choose a reason for hiding this comment

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

This should still work, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a HashWithIndifferentAccess so I wouldn't expect to be able to access :user as a method only with a key.

```


Expand Down Expand Up @@ -797,6 +797,22 @@ params do
end
```

By default Grape 1.x presents the parameters to the endpoint as an
ActiveSupport::HashWithIndifferentAccess. This is a change from 0.x where a
Copy link
Member

Choose a reason for hiding this comment

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

Quote class name.

Hashie::Mash was previously presented.
Copy link
Member

Choose a reason for hiding this comment

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

This and the restore note belongs in UPGRADING, not README. Lets keep it consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's in the UPGRADING I just figured it's a good point to direct them to it. Can remove the paragraph if you prefer?


To restore the previous behaviour check out [UPGRADING](UPGRADING.md).

If you would rather have the parameters presented as a plain old Ruby Hash you
can specify this using build_with in the params block;

```ruby
params do
build_with Grape::Extensions::Hash::ParamBuilder
optional :color, type: String, default: 'blue', values: ['blue', 'red', 'green']
end
Copy link
Member

Choose a reason for hiding this comment

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

Document how to configure this globally with Hash or Hashie::Mash.

```

### Supported Parameter Types

The following are all valid types, supported out of the box by Grape:
Expand Down Expand Up @@ -905,11 +921,14 @@ 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 wrapped using HashWithIndifferentAccess:
params[:avatar][:filename] # => 'avatar.png'
params['avatar']['avatar'] # => 'image/png'
params[:avatar][:tempfile] # => #<File>
Copy link
Member

Choose a reason for hiding this comment

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

The old code works here with HashWithIndifferentAccess default.

end

`params` hash keys can accesed with `""` or `:`
`:avatar` and `"avatar"` are considered to be the same.
Copy link
Member

Choose a reason for hiding this comment

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

The old syntax should work by default, so put that back. And is this true when using Hash? What is it storing?

Ruby programmers know the difference so maybe say "as a string" or "as a symbol".

```

### First-Class `JSON` Types
Expand Down
14 changes: 14 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
Upgrading Grape
===============
### Upgrading to >= 1.0.0
Prior to this version the endpoint was presented with params in the form of a Hashie::Mash. From 1.0.0 upwards Grape presents the parameters to the endpoint as an
ActiveSupport::HashWithIndifferentAccess.

To restore the previous behaviour you can specify Hashie::Mash using build_with in the params block;

```ruby
params do
build_with Grape::Extensions::Hashie::Mash::ParamBuilder
optional :color, type: String, default: 'blue', values: ['blue', 'red', 'green']
end
```

The various options are documented in [Grape::DSL::Parameters](lib/grape/dsl/parameters.rb)
Copy link
Member

@dblock dblock Apr 6, 2017

Choose a reason for hiding this comment

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

Doesn't explain how to do this globally or for an entire API. I have a 500 endpoints, I don't think I can do this everywhere :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you look at the implementation in dsl/parameters. This is actually my first outing with Grape so I wasn't 100% sure about the inheritable parameters so I'd appreciate some eyes on that.

Copy link
Member

Choose a reason for hiding this comment

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

Looks OK to me, just need a way to do this globally. I'm not in love with build_with as a name, but I can't come up with better. Alternatives ideas may be builde or just with?

Either way we need something where I can do this for an entire API.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So currently I've just got build_with defined in lib/grape/dsl/parameters.rb which is fine for the syntax in the local params block. Can you suggest how & where you would like this in Global? I'm on very limited time for this so a big sign post would help.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dblock @namusyaka There are a lot of getter/setters in DSL::Settings, right now I do not have the time to read through all the code and decipher which one to use and how they interact with each other so I'm going to need direction.

I too am not delighted with build_with but couldn't come up with anything better and it kind of made sense in the context of the params block. I don't think it much sense in a global context so very receptive to suggestions of what to call it and where to put it.

Copy link
Member

@dblock dblock Apr 7, 2017

Choose a reason for hiding this comment

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

I think I'd want a mixin, so something like

class API < Grape::API
   include Grape::SomethingSomething::Params::Hashie::Mash

end

One way it could work is by overriding params, but hopefully there's a cleaner way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I couldn't find a clean way via composition as you're mixing into API, but Request creates the params when Endpoint is mounted in API so going that route I ended up passing the class to instantiate through Endpoint and onto Request. Which pretty convoluted given we have a mechanism for sharing parameters across API and Endpoint via the Settings mixin.


### Upgrading to >= 0.19.1

Expand Down
1 change: 1 addition & 0 deletions gemfiles/rack_1.5.2.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ group :development, :test do
gem 'bundler'
gem 'rake'
gem 'rubocop', '0.47.0'
gem 'hashie', require: false
end

group :development do
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rack_edge.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ group :development, :test do
gem 'bundler'
gem 'rake'
gem 'rubocop', '0.47.0'
gem 'hashie', require: false
end

group :development do
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_3.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ group :development, :test do
gem 'bundler'
gem 'rake'
gem 'rubocop', '0.47.0'
gem 'hashie', require: false
end

group :development do
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_4.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ group :development, :test do
gem 'bundler'
gem 'rake'
gem 'rubocop', '0.47.0'
gem 'hashie', require: false
end

group :development do
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_5.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ group :development, :test do
gem 'bundler'
gem 'rake'
gem 'rubocop', '0.47.0'
gem 'hashie', require: false
end

group :development do
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_edge.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ group :development, :test do
gem 'bundler'
gem 'rake'
gem 'rubocop', '0.47.0'
gem 'hashie', require: false
end

group :development do
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
1 change: 0 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 Down
4 changes: 2 additions & 2 deletions lib/grape/dsl/inside_route.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def declared_array(passed_params, options, declared_params)
end

def declared_hash(passed_params, options, declared_params)
declared_params.each_with_object(Hashie::Mash.new) do |declared_param, memo|
declared_params.each_with_object({}) do |declared_param, memo|
# If it is not a Hash then it does not have children.
# Find its value or set it to nil.
if !declared_param.is_a?(Hash)
Expand All @@ -56,7 +56,7 @@ def declared_hash(passed_params, options, declared_params)
declared_param.each_pair do |declared_parent_param, declared_children_params|
next unless options[:include_missing] || passed_params.key?(declared_parent_param)

passed_children_params = passed_params[declared_parent_param] || Hashie::Mash.new
passed_children_params = passed_params[declared_parent_param] || {}
memo[optioned_param_key(declared_parent_param, options)] = declared(passed_children_params, options, declared_children_params)
end
end
Expand Down
25 changes: 25 additions & 0 deletions lib/grape/dsl/parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@ module DSL
module Parameters
extend ActiveSupport::Concern

# Set the module used to build the request.params.
#
# @param build_with the ParamBuilder module to use when building request.params
# Available builders are;
# * Grape::Extensions::HashWithIndifferentAccess::ParamBuilder (default)
# * Grape::Extensions::Hash::ParamBuilder
# * Grape::Extensions::Hashie::Mash::ParamBuilder
#
# @example
#
# require 'grape/extenstions/hashie_mash'
# class API < Grape::API
# desc "Get collection"
# params do
# build_with Grape::Extensions::Hashie::Mash::ParamBuilder
# requires :user_id, type: Integer
# end
# get do
# params['user_id']
# end
# end
def build_with(build_with = nil)
@api.namespace_inheritable(:build_with, build_with)
end

# Include reusable params rules among current.
# You can define reusable params with helpers method.
#
Expand Down
7 changes: 2 additions & 5 deletions lib/grape/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Grape
# blocks are executed. In other words, any methods
# on the instance level of this class may be called
# from inside a `get`, `post`, etc.
class Endpoint
class Endpoint # rubocop:disable ClassLength
include Grape::DSL::Settings
include Grape::DSL::InsideRoute

Expand Down Expand Up @@ -239,15 +239,12 @@ def equals?(e)
def run
ActiveSupport::Notifications.instrument('endpoint_run.grape', endpoint: self, env: env) do
@header = {}

@request = Grape::Request.new(env)
@request = Grape::Request.new(env, build_params_with: namespace_inheritable(:build_with))
@params = @request.params
@headers = @request.headers

cookies.read(@request)

self.class.run_before_each(self)

run_filters befores, :before

if (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
Expand Down
19 changes: 19 additions & 0 deletions lib/grape/extensions/deep_mergeable_hash.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Grape
module Extensions
class DeepMergeableHash < ::Hash
def deep_merge!(other_hash)
other_hash.each_pair do |current_key, other_value|
this_value = self[current_key]

self[current_key] = if this_value.is_a?(::Hash) && other_value.is_a?(::Hash)
this_value.deep_merge(other_value)
else
other_value
end
end

self
end
end
end
end
22 changes: 22 additions & 0 deletions lib/grape/extensions/deep_symbolize_hash.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Grape
module Extensions
module DeepSymbolizeHash
def self.deep_symbolize_keys_in(object)
case object
when ::Hash
object.each_with_object({}) do |(key, value), new_hash|
new_hash[symbolize_key(key)] = deep_symbolize_keys_in(value)
end
when ::Array
object.map { |element| deep_symbolize_keys_in(element) }
else
object
end
end

def self.symbolize_key(key)
key.respond_to?(:to_sym) ? key.to_sym : key
end
end
end
end
19 changes: 19 additions & 0 deletions lib/grape/extensions/hash.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require_relative 'deep_mergeable_hash'
require_relative 'deep_symbolize_hash'
module Grape
module Extensions
module Hash
module ParamBuilder
def build_params
params = Grape::Extensions::DeepMergeableHash[rack_params]
params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
post_process_params(params)
end

def post_process_params(params)
Grape::Extensions::DeepSymbolizeHash.deep_symbolize_keys_in(params)
end
end
end
end
end
17 changes: 17 additions & 0 deletions lib/grape/extensions/hash_with_indifferent_access.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Grape
module Extensions
module HashWithIndifferentAccess
def params_builder
Grape::Extensions::HashWithIndifferentAccess::ParamBuilder
end

module ParamBuilder
def build_params
params = ActiveSupport::HashWithIndifferentAccess[rack_params]
params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
params
end
end
end
end
end
20 changes: 20 additions & 0 deletions lib/grape/extensions/hashie_mash.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'hashie'
module Grape
module Extensions
module Hashie
module Mash
def params_builder
Grape::Extensions::Hashie::Mash::ParamBuilder
end

module ParamBuilder
def build_params
params = ::Hashie::Mash.new(rack_params)
params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
params
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/grape/middleware/globals.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Grape
module Middleware
class Globals < Base
def before
request = Grape::Request.new(@env)
request = Grape::Request.new(@env, build_params_with: @options[:build_params_with])
@env[Grape::Env::GRAPE_REQUEST] = request
@env[Grape::Env::GRAPE_REQUEST_HEADERS] = request.headers
@env[Grape::Env::GRAPE_REQUEST_PARAMS] = request.params if @env[Grape::Env::RACK_INPUT]
Expand Down
Loading