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.
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}}"