remarkable_rails 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +81 -0
- data/LICENSE +20 -0
- data/README +2 -0
- data/lib/remarkable_rails/action_controller/base.rb +31 -0
- data/lib/remarkable_rails/action_controller/macro_stubs.rb +518 -0
- data/lib/remarkable_rails/action_controller/matchers/assign_to_matcher.rb +94 -0
- data/lib/remarkable_rails/action_controller/matchers/filter_params_matcher.rb +41 -0
- data/lib/remarkable_rails/action_controller/matchers/redirect_to_matcher.rb +119 -0
- data/lib/remarkable_rails/action_controller/matchers/render_template_matcher.rb +147 -0
- data/lib/remarkable_rails/action_controller/matchers/respond_with_matcher.rb +125 -0
- data/lib/remarkable_rails/action_controller/matchers/route_matcher.rb +94 -0
- data/lib/remarkable_rails/action_controller/matchers/set_session_matcher.rb +108 -0
- data/lib/remarkable_rails/action_controller/matchers/set_the_flash_matcher.rb +55 -0
- data/lib/remarkable_rails/action_controller.rb +22 -0
- data/lib/remarkable_rails/action_view/base.rb +7 -0
- data/lib/remarkable_rails/action_view.rb +18 -0
- data/lib/remarkable_rails/active_orm.rb +19 -0
- data/lib/remarkable_rails.rb +30 -0
- data/locale/en.yml +87 -0
- data/spec/action_controller/assign_to_matcher_spec.rb +143 -0
- data/spec/action_controller/filter_params_matcher_spec.rb +64 -0
- data/spec/action_controller/macro_stubs_spec.rb +196 -0
- data/spec/action_controller/redirect_to_matcher_spec.rb +102 -0
- data/spec/action_controller/render_template_matcher_spec.rb +251 -0
- data/spec/action_controller/respond_with_matcher_spec.rb +223 -0
- data/spec/action_controller/route_matcher_spec.rb +75 -0
- data/spec/action_controller/set_session_matcher_spec.rb +135 -0
- data/spec/action_controller/set_the_flash_matcher_spec.rb +95 -0
- data/spec/application/application.rb +15 -0
- data/spec/application/examples/_example.html.erb +0 -0
- data/spec/application/examples/example.html.erb +0 -0
- data/spec/application/examples/example.xml.builder +0 -0
- data/spec/application/examples/new.html.erb +0 -0
- data/spec/application/layouts/examples.html.erb +0 -0
- data/spec/application/projects/new.html.erb +0 -0
- data/spec/application/tasks_controller.rb +34 -0
- data/spec/functional_builder.rb +93 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +44 -0
- metadata +134 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActionController
|
3
|
+
module Matchers
|
4
|
+
# Do not inherit from ActionController::Base since it don't need all macro stubs behavior.
|
5
|
+
class RouteMatcher < Remarkable::Base #:nodoc:
|
6
|
+
arguments :method, :path
|
7
|
+
|
8
|
+
assertions :map_to_path?, :generate_params?
|
9
|
+
|
10
|
+
before_assert do
|
11
|
+
@options[:controller] ||= controller_name
|
12
|
+
|
13
|
+
@populated_path = @path.dup
|
14
|
+
|
15
|
+
@options.each do |key, value|
|
16
|
+
@options[key] = value.to_param if value.respond_to?(:to_param)
|
17
|
+
@populated_path.gsub!(key.inspect, value.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
::ActionController::Routing::Routes.reload if ::ActionController::Routing::Routes.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def map_to_path?
|
26
|
+
route_for = ::ActionController::Routing::Routes.generate(@options) rescue nil
|
27
|
+
return route_for == @populated_path, :actual => route_for.inspect
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_params?
|
31
|
+
params_from = ::ActionController::Routing::Routes.recognize_path(@populated_path, :method => @method.to_sym)
|
32
|
+
return params_from == @options, :actual => params_from.inspect
|
33
|
+
end
|
34
|
+
|
35
|
+
# First tries to get the controller name from the subject, then from
|
36
|
+
# the spec class using controller class or finally, from the described
|
37
|
+
# class.
|
38
|
+
#
|
39
|
+
# We have to try the described class because we don't have neither the
|
40
|
+
# subject or the controller class in the RoutingExampleGroup.
|
41
|
+
#
|
42
|
+
def controller_name
|
43
|
+
spec_class = @spec.class unless @spec.class == Class
|
44
|
+
|
45
|
+
controller = if @subject && @subject.class.ancestors.include?(::ActionController::Base)
|
46
|
+
@subject.class
|
47
|
+
elsif spec_class.respond_to?(:controller_class)
|
48
|
+
spec_class.controller_class
|
49
|
+
elsif spec_class.respond_to?(:described_class)
|
50
|
+
spec_class.described_class
|
51
|
+
end
|
52
|
+
|
53
|
+
if controller && controller.ancestors.include?(::ActionController::Base)
|
54
|
+
controller.name.gsub(/Controller$/, '').tableize
|
55
|
+
else
|
56
|
+
raise ArgumentError, "I cannot guess the controller name in route. Please supply :controller as option"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def interpolation_options
|
61
|
+
{ :options => @options.inspect, :method => @method.to_s.upcase, :path => @path.inspect }
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# Assert route generation AND route recognition.
|
67
|
+
#
|
68
|
+
# == Examples
|
69
|
+
#
|
70
|
+
# # autodetects the :controller
|
71
|
+
# should_route :get, '/posts', :action => :index
|
72
|
+
#
|
73
|
+
# # explicitly specify :controller
|
74
|
+
# should_route :post, '/posts', :controller => :posts, :action => :create
|
75
|
+
#
|
76
|
+
# # non-string parameter
|
77
|
+
# should_route :get, '/posts/1', :controller => :posts, :action => :show, :id => 1
|
78
|
+
#
|
79
|
+
# # string-parameter
|
80
|
+
# should_route :put, '/posts/1', :controller => :posts, :action => :update, :id => "1"
|
81
|
+
# should_route :delete, '/posts/1', :controller => :posts, :action => :destroy, :id => 1
|
82
|
+
# should_route :get, '/posts/new', :controller => :posts, :action => :new
|
83
|
+
#
|
84
|
+
# # nested routes
|
85
|
+
# should_route :get, '/users/5/posts', :controller => :posts, :action => :index, :user_id => 5
|
86
|
+
# should_route :post, '/users/5/posts', :controller => :posts, :action => :create, :user_id => 5
|
87
|
+
#
|
88
|
+
def route(*params)
|
89
|
+
RouteMatcher.new(*params).spec(self)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActionController
|
3
|
+
module Matchers
|
4
|
+
class SetSessionMatcher < Remarkable::ActionController::Base #:nodoc:
|
5
|
+
arguments :collection => :keys, :as => :key, :block => :block
|
6
|
+
|
7
|
+
optional :to
|
8
|
+
|
9
|
+
assertion :is_not_empty?, :contains_value?
|
10
|
+
collection_assertions :assigned_value?, :is_equal_value?
|
11
|
+
|
12
|
+
before_assert :evaluate_expected_value
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# When no keys are given:
|
17
|
+
#
|
18
|
+
# should set_session
|
19
|
+
#
|
20
|
+
# We check if the session is not empty.
|
21
|
+
#
|
22
|
+
def is_not_empty?
|
23
|
+
!(@keys.empty? && session.empty?)
|
24
|
+
end
|
25
|
+
|
26
|
+
# When no keys are given and a comparision value is given:
|
27
|
+
#
|
28
|
+
# should set_session.to(1)
|
29
|
+
#
|
30
|
+
# We check if any of the session data contains the given value.
|
31
|
+
#
|
32
|
+
def contains_value?
|
33
|
+
return true unless @keys.empty? && value_to_compare?
|
34
|
+
assert_contains(session.values, @options[:to])
|
35
|
+
end
|
36
|
+
|
37
|
+
def assigned_value?
|
38
|
+
session.key?(@key)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns true if :to is not given and no block is given.
|
42
|
+
# In case :to is a proc or a block is given, we evaluate it in the
|
43
|
+
# @spec scope.
|
44
|
+
#
|
45
|
+
def is_equal_value?
|
46
|
+
return true unless value_to_compare?
|
47
|
+
session[@key] == @options[:to]
|
48
|
+
end
|
49
|
+
|
50
|
+
def session
|
51
|
+
raw_session.with_indifferent_access.except(:flash)
|
52
|
+
end
|
53
|
+
|
54
|
+
def raw_session
|
55
|
+
@subject ? @subject.response.session.data : {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def value_to_compare?
|
59
|
+
@options.key?(:to) || @block
|
60
|
+
end
|
61
|
+
|
62
|
+
def interpolation_options
|
63
|
+
{ :session_inspect => raw_session.except('flash').symbolize_keys!.inspect }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Evaluate procs before assert to avoid them appearing in descriptions.
|
67
|
+
def evaluate_expected_value
|
68
|
+
if value_to_compare?
|
69
|
+
value = @options.key?(:to) ? @options[:to] : @block
|
70
|
+
value = @spec.instance_eval(&value) if value.is_a?(Proc)
|
71
|
+
@options[:to] = value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
# Ensures that a session keys were set. If you want to check that a variable
|
78
|
+
# is not being set, please do:
|
79
|
+
#
|
80
|
+
# should_not_set_session(:user)
|
81
|
+
#
|
82
|
+
# If you want to assure that a variable is being set to nil, do instead:
|
83
|
+
#
|
84
|
+
# should_set_session(:user).to(nil)
|
85
|
+
#
|
86
|
+
# == Options
|
87
|
+
#
|
88
|
+
# * <tt>:to</tt> - The value to compare the session key.
|
89
|
+
# It accepts procs and be also given as a block (see examples below).
|
90
|
+
#
|
91
|
+
# == Examples
|
92
|
+
#
|
93
|
+
# should_set_session :user_id, :user
|
94
|
+
# should_set_session :user_id, :to => 2
|
95
|
+
# should_set_session :user, :to => proc{ users(:first) }
|
96
|
+
# should_set_session(:user){ users(:first) }
|
97
|
+
#
|
98
|
+
# it { should set_session(:user_id, :user) }
|
99
|
+
# it { should set_session(:user_id, :to => 2) }
|
100
|
+
# it { should set_session(:user, :to => users(:first)) }
|
101
|
+
#
|
102
|
+
def set_session(*args, &block)
|
103
|
+
SetSessionMatcher.new(*args, &block).spec(self)
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'set_session_matcher')
|
2
|
+
|
3
|
+
module Remarkable
|
4
|
+
module ActionController
|
5
|
+
module Matchers
|
6
|
+
class SetTheFlashMatcher < SetSessionMatcher #:nodoc:
|
7
|
+
|
8
|
+
protected
|
9
|
+
def session
|
10
|
+
@subject ? (@subject.response.session['flash'] || {}) : {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def interpolation_options
|
14
|
+
{ :flash_inspect => session.symbolize_keys!.inspect }
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
# Ensures that a session keys were set. If you want to check that a flash
|
20
|
+
# is not being set, please do:
|
21
|
+
#
|
22
|
+
# should_not_set_the_flash(:user)
|
23
|
+
#
|
24
|
+
# If you want to assure that a flash is being set to nil, do instead:
|
25
|
+
#
|
26
|
+
# should_set_the_flash(:user).to(nil)
|
27
|
+
#
|
28
|
+
# == Options
|
29
|
+
#
|
30
|
+
# * <tt>:to</tt> - The value to compare the flash key. It accepts procs and can also be given as a block (see examples below)
|
31
|
+
#
|
32
|
+
# == Examples
|
33
|
+
#
|
34
|
+
# should_set_the_flash
|
35
|
+
# should_not_set_the_flash
|
36
|
+
#
|
37
|
+
# should_set_the_flash :to => 'message'
|
38
|
+
# should_set_the_flash :notice, :warn
|
39
|
+
# should_set_the_flash :notice, :to => 'message'
|
40
|
+
# should_set_the_flash :notice, :to => proc{ 'hi ' + users(:first).name }
|
41
|
+
# should_set_the_flash(:notice){ 'hi ' + users(:first).name }
|
42
|
+
#
|
43
|
+
# it { should set_the_flash }
|
44
|
+
# it { should set_the_flash.to('message') }
|
45
|
+
# it { should set_the_flash(:notice, :warn) }
|
46
|
+
# it { should set_the_flash(:notice, :to => 'message') }
|
47
|
+
# it { should set_the_flash(:notice, :to => ('hi ' + users(:first).name)) }
|
48
|
+
#
|
49
|
+
def set_the_flash(*args, &block)
|
50
|
+
SetTheFlashMatcher.new(*args, &block).spec(self)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActionController
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
dir = File.dirname(__FILE__)
|
7
|
+
require File.join(dir, 'action_controller', 'base')
|
8
|
+
require File.join(dir, 'action_controller', 'macro_stubs')
|
9
|
+
|
10
|
+
# Load matchers
|
11
|
+
Dir[File.join(dir, 'action_controller', 'matchers', '*.rb')].each do |file|
|
12
|
+
require file
|
13
|
+
end
|
14
|
+
|
15
|
+
# Include macro_stubs and matchers in Spec::Rails
|
16
|
+
if defined?(Spec::Rails)
|
17
|
+
Spec::Rails::Example::ControllerExampleGroup.send :include, Remarkable::ActionController::MacroStubs
|
18
|
+
|
19
|
+
Remarkable.include_matchers!(Remarkable::ActionController, Spec::Rails::Example::ControllerExampleGroup)
|
20
|
+
Remarkable.include_matchers!(Remarkable::ActionController, Spec::Rails::Example::RoutingExampleGroup)
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActionView
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
dir = File.dirname(__FILE__)
|
7
|
+
require File.join(dir, 'action_view', 'base')
|
8
|
+
|
9
|
+
# Load matchers
|
10
|
+
Dir[File.join(dir, 'action_view', 'matchers', '*.rb')].each do |file|
|
11
|
+
require file
|
12
|
+
end
|
13
|
+
|
14
|
+
# Iinclude matchers in Spec::Rails
|
15
|
+
if defined?(Spec::Rails)
|
16
|
+
Remarkable.include_matchers!(Remarkable::ActionView, Spec::Rails::Example::FunctionalExampleGroup)
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This will responsable to check which ORM is loaded and include respective
|
2
|
+
# matchers.
|
3
|
+
#
|
4
|
+
if defined?(ActiveRecord::Base)
|
5
|
+
unless Remarkable.const_defined?('ActiveRecord')
|
6
|
+
begin
|
7
|
+
require 'remarkable_activerecord'
|
8
|
+
rescue LoadError
|
9
|
+
require 'rubygems'
|
10
|
+
gem 'remarkable_activerecord'
|
11
|
+
require 'remarkable_activerecord'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Include Remarkable ActiveRecord matcher in appropriate ExampleGroup
|
16
|
+
if defined?(Spec::Rails)
|
17
|
+
Remarkable.include_matchers!(Remarkable::ActiveRecord, Spec::Rails::Example::ModelExampleGroup)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Load Remarkable
|
2
|
+
unless Object.const_defined?('Remarkable')
|
3
|
+
begin
|
4
|
+
require 'remarkable'
|
5
|
+
rescue LoadError
|
6
|
+
require 'rubygems'
|
7
|
+
gem 'remarkable'
|
8
|
+
require 'remarkable'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Load spec/rails
|
13
|
+
if defined?(Spec)
|
14
|
+
begin
|
15
|
+
require 'spec/rails'
|
16
|
+
rescue LoadError
|
17
|
+
require 'rubygems'
|
18
|
+
gem 'rspec-rails'
|
19
|
+
require 'spec/rails'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Load Remarkable Rails base files
|
24
|
+
dir = File.dirname(__FILE__)
|
25
|
+
require File.join(dir, 'remarkable_rails', 'active_orm')
|
26
|
+
require File.join(dir, 'remarkable_rails', 'action_controller')
|
27
|
+
require File.join(dir, 'remarkable_rails', 'action_view')
|
28
|
+
|
29
|
+
# Load locale file
|
30
|
+
Remarkable.add_locale File.join(dir, '..', 'locale', 'en.yml')
|
data/locale/en.yml
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
en:
|
2
|
+
remarkable:
|
3
|
+
action_controller:
|
4
|
+
responding: "responding to #{{verb}} {{action}}"
|
5
|
+
mime_type: "with {{format}}"
|
6
|
+
assign_to:
|
7
|
+
description: "assign {{names}}"
|
8
|
+
expectations:
|
9
|
+
assigned_value: "action to assign {{name}}, got no assignment"
|
10
|
+
is_kind_of: "assign {{name}} to be kind of {{with_kind_of}}, got a {{assign_class}}"
|
11
|
+
is_equal_value: "assign {{name}} to be equal to {{with}}, got {{assign_inspect}}"
|
12
|
+
optionals:
|
13
|
+
with_kind_of:
|
14
|
+
positive: "with kind of {{value}}"
|
15
|
+
filter_params:
|
16
|
+
description: "filter {{params}} parameters from log"
|
17
|
+
expectations:
|
18
|
+
respond_to_filter_params: "controller to respond to filter_parameters (controller is not filtering any parameter)"
|
19
|
+
is_filtered: "{{param}} to be filtered, got no filtering"
|
20
|
+
redirect_to:
|
21
|
+
description: "redirect to {{expected}}"
|
22
|
+
expectations:
|
23
|
+
redirected: "redirect to {{expected}}, got no redirect"
|
24
|
+
status_matches: "redirect to {{expected}} with status {{with}}, got status {{status}}"
|
25
|
+
url_matches: "redirect to {{expected}}, got redirect to {{actual}}"
|
26
|
+
optionals:
|
27
|
+
with:
|
28
|
+
positive: "with status {{inspect}}"
|
29
|
+
render_template:
|
30
|
+
description: "render"
|
31
|
+
expectations:
|
32
|
+
rendered: "template {{template}} to be rendered, got no render"
|
33
|
+
template_matches: "template {{template}} to be rendered, got {{actual_template}}"
|
34
|
+
layout_matches: "to render with layout {{layout}}, got {{actual_layout}}"
|
35
|
+
status_matches: "to render with {{with}}, got {{actual_status}}"
|
36
|
+
body_matches: "to render with body equals to {{body}}, got {{actual_body}}"
|
37
|
+
content_type_matches: "to render with content type {{content_type}}, got {{actual_content_type}}"
|
38
|
+
optionals:
|
39
|
+
template:
|
40
|
+
positive: "template {{inspect}}"
|
41
|
+
layout:
|
42
|
+
positive: "with layout {{inspect}}"
|
43
|
+
negative: "with no layout"
|
44
|
+
with:
|
45
|
+
positive: "with {{value}}"
|
46
|
+
body:
|
47
|
+
positive: "with body {{inspect}}"
|
48
|
+
content_type:
|
49
|
+
positive: "with content type {{inspect}}"
|
50
|
+
respond_with:
|
51
|
+
description: "respond"
|
52
|
+
expectations:
|
53
|
+
status_matches: "to respond with {{with}}, got {{actual_status}}"
|
54
|
+
body_matches: "to respond with body equals to {{body}}, got {{actual_body}}"
|
55
|
+
content_type_matches: "to respond with content type {{content_type}}, got {{actual_content_type}}"
|
56
|
+
optionals:
|
57
|
+
with:
|
58
|
+
positive: "with {{value}}"
|
59
|
+
body:
|
60
|
+
positive: "with body {{inspect}}"
|
61
|
+
content_type:
|
62
|
+
positive: "with content type {{inspect}}"
|
63
|
+
route:
|
64
|
+
description: "route {{method}} {{path}} to/from {{options}}"
|
65
|
+
expectations:
|
66
|
+
map_to_path: "to map {{options}} to {{method}} {{path}}, got {{actual}}"
|
67
|
+
generate_params: "to generate params {{options}} from {{method}} {{path}}, got {{actual}}"
|
68
|
+
set_session:
|
69
|
+
description: "set session variable {{keys}}"
|
70
|
+
expectations:
|
71
|
+
is_not_empty: "any session variable to be set, got {{session_inspect}}"
|
72
|
+
contains_value: "any session variable to be set to {{to}}, got {{session_inspect}}"
|
73
|
+
assigned_value: "session variable {{key}} to be set, got {{session_inspect}}"
|
74
|
+
is_equal_value: "session variable {{key}} to be set to {{to}}, got {{session_inspect}}"
|
75
|
+
optionals:
|
76
|
+
to:
|
77
|
+
positive: "to {{inspect}}"
|
78
|
+
set_the_flash:
|
79
|
+
description: "set the flash message {{keys}}"
|
80
|
+
expectations:
|
81
|
+
is_not_empty: "any flash message to be set, got {{flash_inspect}}"
|
82
|
+
contains_value: "any flash message to be set to {{to}}, got {{flash_inspect}}"
|
83
|
+
assigned_value: "flash message {{key}} to be set, got {{flash_inspect}}"
|
84
|
+
is_equal_value: "flash message {{key}} to be set to {{to}}, got {{flash_inspect}}"
|
85
|
+
optionals:
|
86
|
+
to:
|
87
|
+
positive: "to {{inspect}}"
|