remarkable_rails 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG +81 -0
  2. data/LICENSE +20 -0
  3. data/README +2 -0
  4. data/lib/remarkable_rails/action_controller/base.rb +31 -0
  5. data/lib/remarkable_rails/action_controller/macro_stubs.rb +518 -0
  6. data/lib/remarkable_rails/action_controller/matchers/assign_to_matcher.rb +94 -0
  7. data/lib/remarkable_rails/action_controller/matchers/filter_params_matcher.rb +41 -0
  8. data/lib/remarkable_rails/action_controller/matchers/redirect_to_matcher.rb +119 -0
  9. data/lib/remarkable_rails/action_controller/matchers/render_template_matcher.rb +147 -0
  10. data/lib/remarkable_rails/action_controller/matchers/respond_with_matcher.rb +125 -0
  11. data/lib/remarkable_rails/action_controller/matchers/route_matcher.rb +94 -0
  12. data/lib/remarkable_rails/action_controller/matchers/set_session_matcher.rb +108 -0
  13. data/lib/remarkable_rails/action_controller/matchers/set_the_flash_matcher.rb +55 -0
  14. data/lib/remarkable_rails/action_controller.rb +22 -0
  15. data/lib/remarkable_rails/action_view/base.rb +7 -0
  16. data/lib/remarkable_rails/action_view.rb +18 -0
  17. data/lib/remarkable_rails/active_orm.rb +19 -0
  18. data/lib/remarkable_rails.rb +30 -0
  19. data/locale/en.yml +87 -0
  20. data/spec/action_controller/assign_to_matcher_spec.rb +143 -0
  21. data/spec/action_controller/filter_params_matcher_spec.rb +64 -0
  22. data/spec/action_controller/macro_stubs_spec.rb +196 -0
  23. data/spec/action_controller/redirect_to_matcher_spec.rb +102 -0
  24. data/spec/action_controller/render_template_matcher_spec.rb +251 -0
  25. data/spec/action_controller/respond_with_matcher_spec.rb +223 -0
  26. data/spec/action_controller/route_matcher_spec.rb +75 -0
  27. data/spec/action_controller/set_session_matcher_spec.rb +135 -0
  28. data/spec/action_controller/set_the_flash_matcher_spec.rb +95 -0
  29. data/spec/application/application.rb +15 -0
  30. data/spec/application/examples/_example.html.erb +0 -0
  31. data/spec/application/examples/example.html.erb +0 -0
  32. data/spec/application/examples/example.xml.builder +0 -0
  33. data/spec/application/examples/new.html.erb +0 -0
  34. data/spec/application/layouts/examples.html.erb +0 -0
  35. data/spec/application/projects/new.html.erb +0 -0
  36. data/spec/application/tasks_controller.rb +34 -0
  37. data/spec/functional_builder.rb +93 -0
  38. data/spec/rcov.opts +2 -0
  39. data/spec/spec.opts +4 -0
  40. data/spec/spec_helper.rb +44 -0
  41. 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,7 @@
1
+ module Remarkable
2
+ module ActionView
3
+ class Base < Remarkable::Base
4
+
5
+ end
6
+ end
7
+ end
@@ -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}}"