remarkable_rails 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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}}"
|