rack-cookie-monster 1.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.
@@ -0,0 +1,61 @@
1
+ = Rack Cookie Monster
2
+
3
+ A rack middleware library that allows for cookies to be passed through form parameters. Specifically, it merges the specified
4
+ form parameters into the Cookie header of an http request. It gets around the problem of having a flash application which interacts with a web application that uses cookie based sessions.
5
+
6
+ = Contributing
7
+ The environment can be configured by using bundler.
8
+
9
+ gem bundle or rake setup:contrib
10
+
11
+ = Usage
12
+
13
+ <b>Rails Example:</b>
14
+
15
+ # In rails initializer
16
+ Rack::CookieMonster.configure do |c|
17
+ c.eat :_session_id
18
+ c.eat :user_credentials
19
+ c.share_with /^(Adobe|Shockwave) Flash/
20
+ c.share_with "Burt"
21
+ end
22
+
23
+ Rack::CookieMonster.configure_for_rails
24
+
25
+ <b>Rack Example:</b>
26
+
27
+ class CookieMonsterApplication
28
+ def call(env)
29
+ cookies = ::Rack::Request.new(env).cookies
30
+ res = ::Rack::Response.new
31
+ res.write %{
32
+ <html>
33
+ <head>
34
+ <title>Form</title>
35
+ </head>
36
+ <body>
37
+ <form action="/" method="post">
38
+ Cookie 1: <input type="text" name="cookie_1" />
39
+ Cookie 2: <input type="text" name="cookie_2" />
40
+ Non Cookie: <input type="text" name="non_cookie" />
41
+ <input type="submit" />
42
+ </form>
43
+ </body>
44
+ #{
45
+ cookies.map do |k,v|
46
+ "<p>#{k} - #{v}</p>"
47
+ end.join("\n")
48
+ }
49
+ </html>
50
+ }
51
+ res.finish
52
+ end
53
+ end
54
+
55
+ Rack::CookieMonster.configure do |c|
56
+ c.eat :cookie_1
57
+ c.eat :cookie_2
58
+ end
59
+
60
+ use Rack::CookieMonster
61
+ run CookieMonsterApplication.new
@@ -0,0 +1,50 @@
1
+ Feature: Eats Cookies
2
+
3
+ Scenario: Browser with user agent that cookie monster shares with
4
+ Given I go to "/"
5
+ And I fill in "Cookie 1" for the text field named "cookie_1"
6
+ And I fill in "Cookie 2" for the text field named "cookie_2"
7
+ And I fill in "Noncookie" for the text field named "non_cookie"
8
+ When I press "Submit"
9
+ Then I should see "cookies" for
10
+ | name | value |
11
+ | cookie_1 | Cookie 1 |
12
+ | cookie_2 | Cookie 2 |
13
+ But I should not see "cookies" for
14
+ | name | value |
15
+ | non_cookie | Noncookie |
16
+ But I should see "params" for
17
+ | name | value |
18
+ | non_cookie | Noncookie |
19
+
20
+ Scenario: User agent does not match cookie monster's share list
21
+ Given I change my browser to "ie"
22
+ When I go to "/"
23
+ And I fill in "Cookie 1" for the text field named "cookie_1"
24
+ And I fill in "Cookie 2" for the text field named "cookie_2"
25
+ And I fill in "Noncookie" for the text field named "non_cookie"
26
+ When I press "Submit"
27
+ Then I should not see "cookies" for
28
+ | name | value |
29
+ | cookie_1 | Cookie 1 |
30
+ | cookie_2 | Cookie 2 |
31
+ But I should see "params" for
32
+ | name | value |
33
+ | non_cookie | Noncookie |
34
+ | cookie_1 | Cookie 1 |
35
+ | cookie_2 | Cookie 2 |
36
+
37
+ Scenario: Browser that has existing cookies for domain
38
+ Given My browser has the following cookies
39
+ | name | value |
40
+ | session | secrets |
41
+ | creds | street |
42
+ When I go to "/"
43
+ And I fill in "Cookie 1" for the text field named "cookie_1"
44
+ And I press "Submit"
45
+ Then I should see "cookies" for
46
+ | name | value |
47
+ | cookie_1 | Cookie 1 |
48
+ | session | secrets |
49
+ | creds | street |
50
+
@@ -0,0 +1,49 @@
1
+ class CookieMonsterApplication
2
+ def call(env)
3
+ request = ::Rack::Request.new(env)
4
+ cookies = request.cookies
5
+ params = request.params
6
+
7
+ res = ::Rack::Response.new
8
+ res.write %{
9
+ <html>
10
+ <head>
11
+ <title>Form</title>
12
+ </head>
13
+ <body>
14
+ <p>#{env.inspect}</p>
15
+ <form action="/" method="post">
16
+ Cookie 1: <input type="text" name="cookie_1" />
17
+ Cookie 2: <input type="text" name="cookie_2" />
18
+ Non Cookie: <input type="text" name="non_cookie" />
19
+ <input type="submit" value="Submit" />
20
+ </form>
21
+ <div id="cookies">
22
+ #{
23
+ cookies.map do |k,v|
24
+ "<p>#{k} - #{v}</p>"
25
+ end.join("\n")
26
+ }
27
+ </div>
28
+ <div id="params">
29
+ #{
30
+ params.map do |k,v|
31
+ "<p>#{k} - #{v}</p>"
32
+ end.join("\n")
33
+ }
34
+ </div>
35
+ </body>
36
+ </html>
37
+ }
38
+ res.finish
39
+ end
40
+ end
41
+
42
+ Rack::CookieMonster.configure do |c|
43
+ c.eat :cookie_1
44
+ c.eat :cookie_2
45
+ c.share_with /firefox/i
46
+ end
47
+
48
+ use Rack::CookieMonster
49
+ run CookieMonsterApplication.new
@@ -0,0 +1,23 @@
1
+ And %r{I change my browser to "(\w+)"} do |browser|
2
+ $browser = Culerity::RemoteBrowserProxy.new $server, {:browser => browser}
3
+ $browser.extend BrowserExtensions
4
+ end
5
+
6
+ And %r{^I should( not)? see "([^"]+)" for$} do |not_see, container_id, table|
7
+ table.hashes.each do |h|
8
+ container = $browser.div(:id, container_id)
9
+ if not_see
10
+ lambda {
11
+ container.p(:text, "#{h['name']} - #{h['value']}").text
12
+ }.should raise_error(/unable to locate/i)
13
+ else
14
+ container.p(:text, "#{h['name']} - #{h['value']}").text.should_not be_nil
15
+ end
16
+ end
17
+ end
18
+
19
+ Given "My browser has the following cookies" do |table|
20
+ table.hashes.each do |h|
21
+ $browser.add_cookie("localhost", h["name"], h["value"])
22
+ end
23
+ end
@@ -0,0 +1,163 @@
1
+ module BrowserExtensions
2
+ def current_html
3
+ div(:xpath => "/.").html
4
+ end
5
+ end
6
+
7
+ Then %r{^I eval:?(.*)} do |code|
8
+ eval code
9
+ end
10
+
11
+ When %r{^I (am curious|debug)} do |what|
12
+ require 'ruby-debug'
13
+ debugger
14
+ end
15
+
16
+ And "I pass out" do
17
+ sleep
18
+ end
19
+
20
+ Then /I should be redirected to "(.*)"/ do |url|
21
+ $browser.url.should == url
22
+ end
23
+
24
+ When /I press "(.*)"/ do |button|
25
+ $browser.button(:text, button).click
26
+ assert_successful_response
27
+ end
28
+
29
+ When /I follow "(.*)"/ do |link|
30
+ $browser.link(:text, /#{link}/).click
31
+ assert_successful_response
32
+ end
33
+
34
+ When %r{^I browse to "([^"]+)"$} do |url|
35
+ $browser.goto url
36
+ end
37
+
38
+ When %r{^I refresh$} do
39
+ $browser.refresh
40
+ end
41
+
42
+ When /I fill in "(.*)" for "(.*)"/ do |value, field|
43
+ $browser.text_field(:id, find_label(field).for).set(value)
44
+ end
45
+
46
+ And %r{^I select file "([^"]*)" for "([^"]*)"$} do |file, field|
47
+ $browser.file_field(:id, find_label(field).for).set(test_file(file))
48
+ end
49
+
50
+ When %r{^I fill in "([^"]*)" for the text field named "([^"]*)"$} do |value, field|
51
+ $browser.text_field(:name, field).set(value)
52
+ end
53
+
54
+ When "I go back" do
55
+ $browser.back
56
+ end
57
+
58
+ When /I check "(.*)"/ do |field|
59
+ $browser.check_box(:id, find_label(field).for).set(true)
60
+ end
61
+
62
+ When /^I uncheck "(.*)"$/ do |field|
63
+ $browser.check_box(:id, find_label(field).for).set(false)
64
+ end
65
+
66
+ When /I select "(.*)" from "(.*)"/ do |value, field|
67
+ $browser.select_list(:id, find_label(field).for).select value
68
+ end
69
+
70
+ When /I select "(.*)" from select field "(.*)"/ do |value, field|
71
+ $browser.select_list(:name => field).select value
72
+ end
73
+
74
+ When /I choose "(.*)"/ do |field|
75
+ $browser.radio(:id, find_label(field).for).set(true)
76
+ end
77
+
78
+ When /I go to "(.+)"/ do |path|
79
+ $browser.goto @host + path
80
+ assert_successful_response
81
+ end
82
+
83
+ When /I wait for the (AJAX|restful).*/ do |what|
84
+ $browser.wait
85
+ end
86
+
87
+ When %r{I wait (\d+) seconds} do |seconds|
88
+ sleep seconds.to_i
89
+ end
90
+
91
+ Then %r{^I should see "([^"]+)"$} do |text|
92
+ $browser.current_html.should match(text)
93
+ end
94
+
95
+ When /I puts/ do ||
96
+ puts $browser.current_html
97
+ end
98
+
99
+ Then %r{^I should not see "([^"]+)"$} do |text|
100
+ $browser.current_html.should_not match(text)
101
+ end
102
+
103
+ Then %r{^I change "([^"]+)" to "([^"]+)"$} do |field, value|
104
+ $browser.text_field(:id, find_label(field).for).set(value)
105
+ end
106
+
107
+ Then %r{^I should see "([^\"]*)" with value "([^\"]*)"$} do |field_selector, value|
108
+ doc = Nokogiri.HTML($browser.current_html)
109
+ node = doc.at("//*[@id = //label[contains(.,'#{field_selector}')]/@for]")
110
+ node ||= doc.at("##{field_selector}")
111
+ node ||= doc.at("*[@name = '#{field_selector}']")
112
+
113
+ case node.name
114
+ when "input"
115
+ node["value"].should include(value)
116
+ when 'textarea'
117
+ node.text.should include(value)
118
+ else
119
+ raise "Bad field type: don't know how to check value of a node of type #{node.name}. You should add support!"
120
+ end
121
+ end
122
+
123
+ Then %r{^I should see the radio buttons with these settings$} do |table|
124
+ table.raw.each do |label, state|
125
+ radio = $browser.radio(:id, find_label(label).for)
126
+ case state
127
+ when "checked"
128
+ radio.should be_checked
129
+ when "unchecked"
130
+ radio.should_not be_checked
131
+ end
132
+ end
133
+ end
134
+
135
+ Then %r{^I should see the "([^"]+)" form$} do |form|
136
+ $browser.current_html.should have_selector("form##{form}_form")
137
+ end
138
+
139
+ When %r{^I browse$} do ||
140
+ page = $browser.current_html
141
+ puts page
142
+ end
143
+
144
+ def find_label(text)
145
+ $browser.label :text, text
146
+ end
147
+
148
+ def assert_successful_response(allow_bad_response=false)
149
+ status = $browser.page.web_response.status_code
150
+ if(status == 302 || status == 301)
151
+ location = $browser.page.web_response.get_response_header_value('Location')
152
+ puts "Being redirected to #{location}"
153
+ $browser.goto location
154
+ assert_successful_response
155
+ elsif status != 200 and !allow_bad_response
156
+ raise "Browser returned Response Code #{$browser.page.web_response.status_code}"
157
+ end
158
+ end
159
+
160
+ def fill_in_textfield(field, value)
161
+ $browser.text_field(:id, find_label(field).for).set(value)
162
+ end
163
+
@@ -0,0 +1,57 @@
1
+ require 'culerity'
2
+
3
+ SERVER_PID = "server.pid"
4
+
5
+ $port = 9292
6
+ $host = "http://localhost:#{$port}"
7
+
8
+ Before do
9
+ $browser = Culerity::RemoteBrowserProxy.new $server, {:browser => :firefox}
10
+ module BrowserExtensions; end
11
+ $browser.extend BrowserExtensions
12
+ @host = $host
13
+ @port = $port
14
+ end
15
+
16
+ def kill_test_server
17
+ if File.exist?(SERVER_PID)
18
+ test_server_pid = File.read(SERVER_PID).to_i
19
+ puts "Killing #{test_server_pid}"
20
+ Process.kill "KILL", test_server_pid
21
+ File.delete SERVER_PID
22
+ end
23
+ end
24
+
25
+ def host_listening_on_port?(host, port, timeout=0)
26
+ start_time = Time.now
27
+ begin
28
+ socket = TCPSocket.open(host, port)
29
+ socket.close
30
+ return true
31
+ rescue Errno::ECONNREFUSED
32
+ if Time.now - start_time < timeout
33
+ # try to connect again
34
+ sleep 0.25
35
+ retry
36
+ else
37
+ return false
38
+ end
39
+ end
40
+ end
41
+
42
+
43
+ if host_listening_on_port? "localhost", $port
44
+ puts "Server already running on test port. Killing it..."
45
+ kill_test_server
46
+ end
47
+
48
+ %x(bin/rackup --require lib/rack/cookie_monster --require vendor/gems/environment --daemon --pid #{SERVER_PID} --server webrick features/monster.ru)
49
+ raise "Couldn't start server" unless host_listening_on_port? "localhost", $port, 10
50
+
51
+ $server ||= Culerity::run_server
52
+
53
+ at_exit do
54
+ kill_test_server
55
+ $browser.exit
56
+ $server.close
57
+ end
@@ -0,0 +1,104 @@
1
+ module Rack
2
+ class CookieMonster
3
+
4
+ class Hungry < StandardError; end
5
+
6
+ class<<self
7
+ def configure
8
+ @config ||= CookieMonsterConfig.new
9
+ yield(@config)
10
+ @configured = true
11
+ end
12
+
13
+ def snackers
14
+ ensure_monster_configured!
15
+ @config.snackers
16
+ end
17
+
18
+ def cookies
19
+ ensure_monster_configured!
20
+ @config.cookies
21
+ end
22
+
23
+ def configure_for_rails
24
+ ensure_monster_configured!
25
+ ActionController::Dispatcher.middleware.insert_before(
26
+ ActionController::Base.session_store,
27
+ self
28
+ )
29
+ end
30
+
31
+ private
32
+
33
+ def ensure_monster_configured!
34
+ raise Hungry.new("Cookie Monster has not been configured") unless @configured
35
+ end
36
+
37
+ end
38
+
39
+ def initialize(app)
40
+ @app = app
41
+ end
42
+
43
+ def call(env)
44
+ shares_with(env["HTTP_USER_AGENT"]) do
45
+ request = ::Rack::Request.new(env)
46
+ eat_cookies!(env, request)
47
+ end
48
+ @app.call(env)
49
+ end
50
+
51
+ private
52
+
53
+ def shares_with(agent)
54
+ yield if self.class.snackers.empty?
55
+
56
+ any_matches = self.class.snackers.any? do |snacker|
57
+ case snacker
58
+ when String
59
+ snacker == agent
60
+ when Regexp
61
+ snacker.match(agent) != nil
62
+ end
63
+ end
64
+
65
+ yield if any_matches
66
+ end
67
+
68
+ def eat_cookies!(env, request)
69
+ cookies = request.cookies
70
+ new_cookies = {}
71
+
72
+ self.class.cookies.each do |cookie_name|
73
+ value = request.params[cookie_name.to_s]
74
+ if value
75
+ cookies.delete(cookie_name.to_s)
76
+ new_cookies[cookie_name.to_s] = value
77
+ end
78
+ end
79
+
80
+ new_cookies.merge!(cookies)
81
+ env["HTTP_COOKIE"] = new_cookies.map do |k,v|
82
+ "#{k}=#{v}"
83
+ end.compact.join("; ").freeze
84
+ end
85
+
86
+ end
87
+
88
+ class CookieMonsterConfig
89
+ attr_reader :cookies, :snackers
90
+
91
+ def initialize
92
+ @cookies = []
93
+ @snackers = []
94
+ end
95
+
96
+ def eat(cookie)
97
+ @cookies << cookie.to_sym
98
+ end
99
+
100
+ def share_with(snacker)
101
+ @snackers << snacker
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+ require 'rack/cookie_monster'
3
+ require 'action_controller'
4
+
5
+ describe Rack::CookieMonster do
6
+ subject { Class.new(described_class) }
7
+
8
+ describe ".configure" do
9
+
10
+ it "specifies what cookies are to be eaten" do
11
+ subject.configure do |c|
12
+ c.eat :_session_id
13
+ c.eat :user_credentials
14
+ end
15
+
16
+ subject.cookies.should == [:_session_id, :user_credentials]
17
+ end
18
+
19
+ it "turns the cookie keys into symbols" do
20
+ subject.configure do |c|
21
+ c.eat "burt"
22
+ end
23
+
24
+ subject.cookies.should == [:burt]
25
+ end
26
+
27
+ it "specifies what user agents can snack" do
28
+ subject.configure do |c|
29
+ c.share_with "MSIE 6.0"
30
+ c.share_with /safari \d+/
31
+ end
32
+
33
+ subject.snackers.should == ["MSIE 6.0", /safari \d+/]
34
+ end
35
+
36
+ it "raises an error if it is not configured" do
37
+ lambda { subject.cookies }.should raise_error(Rack::CookieMonster::Hungry, /not been configured/i)
38
+ lambda { subject.snackers }.should raise_error(Rack::CookieMonster::Hungry, /not been configured/i)
39
+ lambda { subject.configure_for_rails }.should raise_error(Rack::CookieMonster::Hungry, /not been configured/i)
40
+ end
41
+ end
42
+
43
+ describe ".configure_for_rails" do
44
+ it "injects itself into the rails request stack" do
45
+ subject.configure {}
46
+ subject.configure_for_rails
47
+ ActionController::Dispatcher.middleware[2].should == subject
48
+ ActionController::Dispatcher.middleware[3].should == ActionController::Session::CookieStore
49
+ end
50
+ end
51
+
52
+ describe "#call" do
53
+ before do
54
+ @target = subject.new(stub_instance(:app))
55
+ @environment = {
56
+ "HTTP_COOKIE" => "",
57
+ "QUERY_STRING" => "oatmeal_cookie=delicious&chocolate_cookie=yummy&burt=ernie&oats=honey",
58
+ "REQUEST_METHOD" => "PUT"
59
+ }
60
+
61
+ subject.configure do |c|
62
+ c.eat :oatmeal_cookie
63
+ c.eat :chocolate_cookie
64
+ end
65
+
66
+ @app.stubs(:call)
67
+ end
68
+
69
+ it "builds cookie string from environment params" do
70
+ @app.expects(:call).with do |env|
71
+ env["HTTP_COOKIE"].should == "chocolate_cookie=yummy; oatmeal_cookie=delicious"
72
+ env["HTTP_COOKIE"].should be_frozen
73
+ end
74
+
75
+ @target.call(@environment)
76
+ end
77
+
78
+ it "will play nice with existing cookies" do
79
+ @environment["HTTP_COOKIE"] = "oatmeal_cookie=gross; peanutbutter_cookie=good"
80
+
81
+ @app.expects(:call).with do |env|
82
+ env["HTTP_COOKIE"].should == "peanutbutter_cookie=good; chocolate_cookie=yummy; oatmeal_cookie=delicious"
83
+ end
84
+
85
+ @target.call(@environment)
86
+ end
87
+
88
+ it "will not append an empty cookie" do
89
+ @environment["QUERY_STRING"] = ""
90
+ @app.expects(:call).with do |env|
91
+ env["HTTP_COOKIE"].should == ""
92
+ env["HTTP_COOKIE"].should be_frozen
93
+ end
94
+
95
+ @target.call(@environment)
96
+ end
97
+
98
+ describe "optional user agents" do
99
+ before do
100
+ subject.configure do |c|
101
+ c.share_with /^(Adobe|Shockwave) Flash/
102
+ c.share_with "MSIE 6.0"
103
+ end
104
+ @cookies = "chocolate_cookie=yummy; oatmeal_cookie=delicious"
105
+ end
106
+
107
+ it "will match against regular expressions" do
108
+
109
+ @app.expects(:call).with(has_entry("HTTP_COOKIE", @cookies)).twice
110
+ @app.expects(:call).with(has_entry("HTTP_COOKIE", "")).once
111
+
112
+ @environment["HTTP_USER_AGENT"] = "Shockwave Flash"
113
+ @target.call(@environment.dup)
114
+ @environment["HTTP_USER_AGENT"] = "Adobe Flash"
115
+ @target.call(@environment.dup)
116
+ @environment["HTTP_USER_AGENT"] = "Flash"
117
+ @target.call(@environment.dup)
118
+ end
119
+
120
+ it "will exact match against strings" do
121
+ @app.expects(:call).with(has_entry("HTTP_COOKIE", @cookies)).once
122
+ @app.expects(:call).with(has_entry("HTTP_COOKIE", "")).once
123
+
124
+ @environment["HTTP_USER_AGENT"] = "MSIE 6.0"
125
+ @target.call(@environment.dup)
126
+ @environment["HTTP_USER_AGENT"] = "MSIE"
127
+ @target.call(@environment.dup)
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,15 @@
1
+ here = File.expand_path(File.dirname(__FILE__))
2
+ require File.join(here, "..", "vendor/gems/environment")
3
+ require File.join(here, "..", "init")
4
+
5
+ require 'spec/autorun'
6
+ require 'mocha'
7
+ require 'active_support'
8
+ require 'rack'
9
+
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
+
12
+ Spec::Runner.configure do |config|
13
+ config.include(SpecInstanceHelpers)
14
+ config.mock_with :mocha
15
+ end
@@ -0,0 +1,164 @@
1
+ module SpecInstanceHelpers
2
+ def stub_instance_hash(*instance_names)
3
+ hash = {}
4
+ instance_names.each do |instance_name|
5
+ hash[instance_name] = stub_instance(instance_name)
6
+ end
7
+ hash
8
+ end
9
+
10
+ def stub_string_hash(*instance_names)
11
+ hash = {}
12
+ instance_names.each do |instance_name|
13
+ hash[instance_name] = stub_string(instance_name)
14
+ end
15
+ hash
16
+ end
17
+
18
+ def create_array_of_stubs(instance, count, stubbings)
19
+ stub_array = stub_array_instance(instance, count, instance.to_s.singularize)
20
+ stub_array.each do |stub|
21
+ stubbings.each do |key, value_lambda|
22
+ stub.stub!(key).and_return(value_lambda.call)
23
+ end
24
+ end
25
+ end
26
+
27
+ def stub_instance(var_name, options={})
28
+ var_name = var_name.to_s.gsub(/[\?!]/, "")
29
+ the_stub = stub(var_name.to_s.humanize, options)
30
+ instance_variable_set("@#{var_name}", the_stub)
31
+ the_stub
32
+ end
33
+
34
+ def stub_array_instance(ivar_sym, count, label=nil)
35
+ label ||= ivar_sym.to_s.singularize
36
+ array = stub_array(count, label)
37
+ instance_variable_set("@#{ivar_sym}", array)
38
+ array
39
+ end
40
+
41
+ def stub_array(count, label)
42
+ array = []
43
+ 1.upto(count) do |i|
44
+ array << stub("#{label} #{i}")
45
+ end
46
+ array
47
+ end
48
+
49
+ def stub_instances(*var_names)
50
+ var_names.map do |var_name|
51
+ stub_instance var_name
52
+ end
53
+ end
54
+
55
+ def stub_params(*param_names)
56
+ @params = {}
57
+ param_names.each do |param_name|
58
+ instance_variable_set("@#{param_name}", "param #{param_name}")
59
+ @params[param_name.to_s] = "param #{param_name}"
60
+ end
61
+ @params
62
+ end
63
+
64
+ def stub_partial(partial, options={})
65
+ options = _prepare_stub_partial_options(partial, options)
66
+ template.stub!(:render).with(options).and_return(%|<p id="#{partial.gsub(/\//,'_')}_partial"></p>|)
67
+ end
68
+
69
+ def stub_partials(*partials)
70
+ partials.each &method(:stub_partial)
71
+ end
72
+
73
+ def stub_string(sym)
74
+ the_stub = sym.to_s.humanize
75
+ instance_variable_set("@#{sym}", the_stub)
76
+ the_stub
77
+ end
78
+
79
+ def stub_strings(*syms)
80
+ syms.each &method(:stub_string)
81
+ end
82
+
83
+ def stub_for_view(name, field_names)
84
+ the_stub = stub_instance(name)
85
+ _stub_methods_for_view(the_stub, field_names)
86
+ the_stub
87
+ end
88
+
89
+
90
+
91
+ def expect_and_render_partial(partial,options={})
92
+ options = _prepare_stub_partial_options(partial, options)
93
+ template.should_receive(:render).with(options).and_return(%|<p id="#{partial.gsub(/\//,'_')}_partial"></p>|)
94
+ end
95
+
96
+ def _stub_methods_for_view(the_stub, field_names)
97
+ field_names.each do |fname|
98
+ case fname
99
+ when String, Symbol
100
+ field_name = fname.to_sym
101
+ field_value = block_given? ? yield(fname) : "The #{fname.to_s.humanize}"
102
+ the_stub.stub!(field_name).and_return(field_value)
103
+ when Hash
104
+ fname.each do |k,v|
105
+ the_stub.stub!(k.to_sym).and_return(v)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def _prepare_stub_partial_options(partial, options)
112
+ options.reverse_merge!(:partial => partial)
113
+ if options[:locals] == false
114
+ options.delete(:locals)
115
+ else
116
+ options.reverse_merge!(:locals => anything)
117
+ end
118
+ options
119
+ end
120
+
121
+ def stub_array_for_view(count, name_base, field_names)
122
+ the_array = []
123
+ count.times do |i|
124
+ i = i + 1 # one-based numbering
125
+ name = "#{name_base.to_s.singularize}#{i}"
126
+ the_stub = stub_instance(name)
127
+ _stub_methods_for_view(the_stub, field_names) do |fname|
128
+ "The #{fname.to_s.humanize} #{i}"
129
+ end
130
+ the_array << the_stub
131
+ end
132
+ instance_variable_set("@#{name_base}", the_array)
133
+ the_array
134
+ end
135
+
136
+
137
+ end
138
+
139
+ class NilClass
140
+ # Mocha:
141
+
142
+ def expects(*args)
143
+ raise "Don't expects(#{args.inspect}) on nil"
144
+ end
145
+
146
+ def stubs(*args)
147
+ raise "Don't stubs(#{args.inspect}) on nil"
148
+ end
149
+
150
+ # RSpec mocks:
151
+ #
152
+ def stub!(*args)
153
+ raise "Don't stub! on nil."
154
+ end
155
+
156
+ def should_receive(*args)
157
+ raise "Don't should_receive on nil."
158
+ end
159
+
160
+ def should_not_receive(*args)
161
+ raise "Don't should_not_receive on nil."
162
+ end
163
+
164
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-cookie-monster
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Justin DeWind
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-15 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rack
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.0
24
+ version:
25
+ description: A rack middleware library that allows cookies to be passed through forms
26
+ email: dewind@atomicobject.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - lib/rack/cookie_monster.rb
35
+ - README.rdoc
36
+ has_rdoc: true
37
+ homepage: http://github.com/dewind/rack-cookie-monster
38
+ licenses: []
39
+
40
+ post_install_message:
41
+ rdoc_options:
42
+ - --charset=UTF-8
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.3.5
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: A rack middleware library that allows cookies to be passed through forms
64
+ test_files:
65
+ - spec/rack/cookie_monster_spec.rb
66
+ - spec/spec_helper.rb
67
+ - spec/support/stub_helpers.rb
68
+ - features/cookie_monster.feature
69
+ - features/monster.ru
70
+ - features/step_definitions/all_steps.rb
71
+ - features/step_definitions/common_celerity.rb
72
+ - features/support/celerity_startup.rb