rack-cookie-monster 1.0.0

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