Skip to content

Commit

Permalink
Merge branch 'master' into 0.7.x
Browse files Browse the repository at this point in the history
  • Loading branch information
jodosha committed Jun 1, 2016
2 parents 2f8fb5b + e6ed4f7 commit 003f357
Show file tree
Hide file tree
Showing 27 changed files with 747 additions and 609 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
language: ruby
sudo: false
cache: bundler
script: 'bundle exec rake test:coverage --trace'
script: 'script/ci'
before_install:
- rvm get head # required by JRuby > 9.0.1.0
- rvm reload
rvm:
- 2.2.4
- 2.3.0
- 2.2.5
- 2.3.1
- ruby-head
- jruby-9.0.5.0
- jruby-head
Expand Down
17 changes: 13 additions & 4 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
source 'http://rubygems.org'
gemspec

if !ENV['TRAVIS']
unless ENV['TRAVIS']
gem 'byebug', require: false, platforms: :mri
gem 'yard', require: false
end

gem 'hanami-utils', '~> 0.8', require: false, github: 'hanami/utils', branch: '0.8.x'
gem 'hanami-router', '~> 0.7', require: false, github: 'hanami/router', branch: '0.7.x'
gem 'hanami-validations', '~> 0.6', require: false, github: 'hanami/validations', branch: '0.6.x'
gem 'minitest', '~> 5.8'
gem 'hanami-utils', '~> 0.8', require: false, github: 'hanami/utils', branch: '0.8.x'
gem 'hanami-router', '~> 0.7', require: false, github: 'hanami/router', branch: '0.7.x'

group :validations do
gem 'hanami-validations', '~> 0.6', require: false, github: 'hanami/validations'

# This is required until dry-validation 0.8 will be out
gem 'dry-types', require: false, github: 'dry-rb/dry-types'
gem 'dry-logic', require: false, github: 'dry-rb/dry-logic'
gem 'dry-validation', require: false, github: 'dry-rb/dry-validation'
end

gem 'coveralls', require: false
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class Show
include Hanami::Action

def call(params)
@article = Article.find params[:id]
@article = ArticleRepository.find params[:id]
end
end
```
Expand All @@ -74,15 +74,15 @@ This is important, because you can implement your own initialization strategy.
__An action is an object__. That's important because __you have the full control on it__.
In other words, you have the freedom to instantiate, inject dependencies and test it, both at the unit and integration level.

In the example below, the default repository is `Article`. During a unit test we can inject a stubbed version, and invoke `#call` with the params.
In the example below, the default repository is `ArticleRepository`. During a unit test we can inject a stubbed version, and invoke `#call` with the params.
__We're avoiding HTTP calls__, we're also going to avoid hitting the database (it depends on the stubbed repository), __we're just dealing with message passing__.
Imagine how **fast** the unit test could be.

```ruby
class Show
include Hanami::Action

def initialize(repository = Article)
def initialize(repository = ArticleRepository)
@repository = repository
end

Expand Down Expand Up @@ -280,7 +280,7 @@ class Show
expose :article

def call(params)
@article = Article.find params[:id]
@article = ArticleRepository.find params[:id]
end
end

Expand Down Expand Up @@ -312,7 +312,7 @@ class Show

# `params` in the method signature is optional
def set_article(params)
@article = Article.find params[:id]
@article = ArticleRepository.find params[:id]
end
end
```
Expand All @@ -324,7 +324,7 @@ class Show
include Hanami::Action

before { ... } # do some authentication stuff
before { |params| @article = Article.find params[:id] }
before { |params| @article = ArticleRepository.find params[:id] }

def call(params)
end
Expand Down Expand Up @@ -356,7 +356,7 @@ class Show
handle_exception RecordNotFound => 404

def call(params)
@article = Article.find params[:id]
@article = ArticleRepository.find params[:id]
end
end

Expand Down Expand Up @@ -397,7 +397,7 @@ class Show
include Hanami::Action

def call(params)
@article = Article.find params[:id]
@article = ArticleRepository.find params[:id]
end
end

Expand All @@ -423,7 +423,7 @@ module Articles
end

def call(params)
@article = Article.find params[:id]
@article = ArticleRepository.find params[:id]
end
end
end
Expand Down Expand Up @@ -991,10 +991,10 @@ The following examples are valid constructors:
def initialize
end

def initialize(repository = Article)
def initialize(repository = ArticleRepository)
end

def initialize(repository: Article)
def initialize(repository: ArticleRepository)
end

def initialize(options = {})
Expand Down
5 changes: 4 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ require 'rake/testtask'
require 'bundler/gem_tasks'

Rake::TestTask.new do |t|
t.pattern = 'test/**/*_test.rb'
t.test_files = Dir['test/**/*_test.rb'].reject do |path|
path.include?('isolation')
end

t.libs.push 'test'
end

Expand Down
6 changes: 2 additions & 4 deletions hanami-controller.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ Gem::Specification.new do |spec|
spec.require_paths = ['lib']
spec.required_ruby_version = '>= 2.2.0'

spec.add_dependency 'rack', '~> 1.6', '>= 1.6.2'
spec.add_dependency 'hanami-utils', '~> 0.8'
spec.add_dependency 'hanami-validations', '~> 0.6'
spec.add_dependency 'rack', '~> 1.6', '>= 1.6.2'
spec.add_dependency 'hanami-utils', '~> 0.8'

spec.add_development_dependency 'bundler', '~> 1.6'
spec.add_development_dependency 'minitest', '~> 5'
spec.add_development_dependency 'rack-test', '~> 0.6'
spec.add_development_dependency 'rake', '~> 11'
end
10 changes: 7 additions & 3 deletions lib/hanami/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
require 'hanami/action/exposable'
require 'hanami/action/throwable'
require 'hanami/action/callbacks'
require 'hanami/action/validatable'
begin
require 'hanami/validations'
require 'hanami/action/validatable'
rescue LoadError
end
require 'hanami/action/head'
require 'hanami/action/callable'

Expand Down Expand Up @@ -53,7 +57,7 @@ def self.included(base)
include Exposable
include Throwable
include Callbacks
include Validatable
include Validatable if defined?(Validatable)
include Configurable
include Head
prepend Callable
Expand All @@ -65,7 +69,7 @@ def self.included(base)
# Finalize the response
#
# This method is abstract and COULD be implemented by included modules in
# order to prepare their data before the reponse will be returned to the
# order to prepare their data before the response will be returned to the
# webserver.
#
# @since 0.1.0
Expand Down
136 changes: 136 additions & 0 deletions lib/hanami/action/base_params.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
require 'rack/request'
require 'hanami/utils/hash'

module Hanami
module Action
class BaseParams
# The key that returns raw input from the Rack env
#
# @since x.x.x
RACK_INPUT = 'rack.input'.freeze

# The key that returns router params from the Rack env
# This is a builtin integration for Hanami::Router
#
# @since x.x.x
ROUTER_PARAMS = 'router.params'.freeze

# Separator for #get
#
# @since x.x.x
# @api private
#
# @see Hanami::Action::Params#get
GET_SEPARATOR = '.'.freeze

# @attr_reader env [Hash] the Rack env
#
# @since x.x.x
# @api private
attr_reader :env

# @attr_reader raw [Hash] the raw params from the request
#
# @since x.x.x
# @api private
attr_reader :raw

# Initialize the params and freeze them.
#
# @param env [Hash] a Rack env or an hash of params.
#
# @return [Params]
#
# @since x.x.x
def initialize(env)
@env = env
@raw = _extract_params
@params = Utils::Hash.new(@raw).symbolize!.to_h
freeze
end

# Returns the object associated with the given key
#
# @param key [Symbol] the key
#
# @return [Object,nil] return the associated object, if found
#
# @since x.x.x
def [](key)
@params[key]
end

# Get an attribute value associated with the given key.
# Nested attributes are reached with a dot notation.
#
# @param key [String] the key
#
# @return [Object,NilClass] return the associated value, if found
#
# @since x.x.x
#
# @example
# require 'hanami/controller'
#
# module Deliveries
# class Create
# include Hanami::Action
#
# def call(params)
# params.get('customer_name') # => "Luca"
# params.get('uknown') # => nil
#
# params.get('address.city') # => "Rome"
# params.get('address.unknown') # => nil
#
# params.get(nil) # => nil
# end
# end
# end
def get(key)
key, *keys = key.to_s.split(GET_SEPARATOR)
result = self[key.to_sym]

Array(keys).each do |k|
break if result.nil?
result = result[k.to_sym]
end

result
end

# Serialize params to Hash
#
# @return [::Hash]
#
# @since x.x.x
def to_h
@params
end
alias_method :to_hash, :to_h

private

# @since x.x.x
# @api private
def _extract_params
result = {}

if env.key?(RACK_INPUT)
result.merge! ::Rack::Request.new(env).params
result.merge! _router_params
else
result.merge! _router_params(env)
end

result
end

# @since x.x.x
# @api private
def _router_params(fallback = {})
env.fetch(ROUTER_PARAMS, fallback)
end
end
end
end
2 changes: 0 additions & 2 deletions lib/hanami/action/callable.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require 'hanami/action/params'

module Hanami
module Action
module Callable
Expand Down
27 changes: 26 additions & 1 deletion lib/hanami/action/cookie_jar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ def initialize(env, headers, default_options)
# @see Hanami::Action::Cookies#finish
def finish
@cookies.delete(RACK_SESSION_KEY)
@cookies.each { |k,v| v.nil? ? delete_cookie(k) : set_cookie(k, _merge_default_values(v)) }
@cookies.each do |k,v|
next unless changed?(k)
v.nil? ? delete_cookie(k) : set_cookie(k, _merge_default_values(v))
end if changed?
end

# Returns the object associated with the given key
Expand Down Expand Up @@ -103,11 +106,33 @@ def [](key)
#
# @see http://en.wikipedia.org/wiki/HTTP_cookie
def []=(key, value)
changes << key
@cookies[key] = value
end

private

# Keep track of changed keys
#
# @since x.x.x
# @api private
def changes
@changes ||= Set.new
end

# Check if the entire set of cookies has changed within the current request.
# If <tt>key</tt> is given, it checks the associated cookie has changed.
#
# @since x.x.x
# @api private
def changed?(key = nil)
if key.nil?
changes.any?
else
changes.include?(key)
end
end

# Merge default cookies options with values provided by user
#
# Cookies values provided by user are respected
Expand Down
5 changes: 4 additions & 1 deletion lib/hanami/action/exposable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ module Exposable
#
# @see http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
def self.included(base)
base.extend ClassMethods
base.class_eval do
extend ClassMethods
expose :params
end
end

# Exposures API class methods
Expand Down
Loading

0 comments on commit 003f357

Please sign in to comment.