Skip to content

Commit

Permalink
Added Merb support.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gwyn Morfey committed Apr 16, 2008
1 parent 13b0ec7 commit cdafd2e
Show file tree
Hide file tree
Showing 10 changed files with 401 additions and 66 deletions.
28 changes: 5 additions & 23 deletions Manifest.txt
@@ -1,26 +1,3 @@
.git/HEAD
.git/config
.git/description
.git/hooks/applypatch-msg
.git/hooks/commit-msg
.git/hooks/post-commit
.git/hooks/post-receive
.git/hooks/post-update
.git/hooks/pre-applypatch
.git/hooks/pre-commit
.git/hooks/pre-rebase
.git/hooks/update
.git/index
.git/info/exclude
.git/logs/HEAD
.git/logs/refs/heads/master
.git/logs/refs/remotes/origin/master
.git/objects/pack/pack-3243faf8e8f6f0e226adf39a2c2e8c19c18da6c4.idx
.git/objects/pack/pack-3243faf8e8f6f0e226adf39a2c2e8c19c18da6c4.pack
.git/refs/heads/master
.git/refs/remotes/origin/HEAD
.git/refs/remotes/origin/master
.gitignore
History.txt
MIT-LICENSE.txt
Manifest.txt
Expand All @@ -38,6 +15,11 @@ lib/webrat/logging.rb
lib/webrat/page.rb
lib/webrat/redirect_actions.rb
lib/webrat/select_option.rb
lib/boot_merb.rb
lib/boot_rails.rb
lib/merb_support/indifferent_access.rb
lib/merb_support/param_parser.rb
lib/merb_support/url_encoded_pair_parser.rb
test/checks_test.rb
test/chooses_test.rb
test/clicks_button_test.rb
Expand Down
84 changes: 84 additions & 0 deletions lib/boot_merb.rb
@@ -0,0 +1,84 @@
#In Merb, we have an RspecStory instead of an integration Session.
class Merb::Test::RspecStory

#Our own redirect actions defined below, to deal with the fact that we need to store
#a controller reference.

def current_page
@current_page ||= Webrat::Page.new(self)
end

def current_page=(new_page)
@current_page = new_page
end

# Issues a GET request for a page, follows any redirects, and verifies the final page
# load was successful.
#
# Example:
# visits "/"
def visits(*args)
@current_page = Webrat::Page.new(self, *args)
end

def save_and_open_page
current_page.save_and_open
end

[:reloads, :fills_in, :clicks_button, :selects, :chooses, :checks, :unchecks, :clicks_link, :clicks_link_within, :clicks_put_link, :clicks_get_link, :clicks_post_link, :clicks_delete_link].each do |method_name|
define_method(method_name) do |*args|
current_page.send(method_name, *args)
end
end

#Session defines the following (used by webrat), but RspecStory doesn't. Merb's get/put/delete return a controller,
#which is where we get our status and response from.
def get_via_redirect(path, parameters = {}, headers = {})
@controller=get path, parameters, headers
follow_redirect! while redirect?
status
end
def put_via_redirect(path, parameters = {}, headers = {})
@controller=put path, parameters, headers
follow_redirect! while redirect?
status
end
def delete_via_redirect(path, parameters = {}, headers = {})
@controller=delete path, parameters, headers
follow_redirect! while redirect?
status
end

def follow_redirect!
@controller=get @controller.headers["Location"]
end

def redirect?
[307, *(300..305)].include?(status)
end

def status
@controller.status
end

def response
@controller #things like @controller.body will work.
end

def assert_response(resp)
if resp == :success
response.should be_successful
else
raise "assert_response #{resp.inspect} is not supported"
end
end
end

#Other utilities used by Webrat that are present in Rails but not Merb. We can require heavy dependencies
#here because we're only loaded in Test mode.
require 'strscan'
require 'cgi'
require File.join(File.dirname(__FILE__), "merb_support", "param_parser.rb")
require File.join(File.dirname(__FILE__), "merb_support", "url_encoded_pair_parser.rb")
require File.join(File.dirname(__FILE__), "merb_support", "indifferent_access.rb")

39 changes: 39 additions & 0 deletions lib/boot_rails.rb
@@ -0,0 +1,39 @@
module ActionController
module Integration
class Session

unless instance_methods.include?("put_via_redirect")
include Webrat::RedirectActions
end

def current_page
@current_page ||= Webrat::Page.new(self)
end

def current_page=(new_page)
@current_page = new_page
end

# Issues a GET request for a page, follows any redirects, and verifies the final page
# load was successful.
#
# Example:
# visits "/"
def visits(*args)
@current_page = Webrat::Page.new(self, *args)
end

def save_and_open_page
current_page.save_and_open
end

[:reloads, :fills_in, :clicks_button, :selects, :chooses, :checks, :unchecks, :clicks_link, :clicks_link_within, :clicks_put_link, :clicks_get_link, :clicks_post_link, :clicks_delete_link].each do |method_name|
define_method(method_name) do |*args|
current_page.send(method_name, *args)
end
end

end
end
end

138 changes: 138 additions & 0 deletions lib/merb_support/indifferent_access.rb
@@ -0,0 +1,138 @@
# This class has dubious semantics and we only have it so that
# people can write params[:key] instead of params['key']
# and they get the same value for both keys.

class HashWithIndifferentAccess < Hash
def initialize(constructor = {})
if constructor.is_a?(Hash)
super()
update(constructor)
else
super(constructor)
end
end

def default(key = nil)
if key.is_a?(Symbol) && include?(key = key.to_s)
self[key]
else
super
end
end

alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
alias_method :regular_update, :update unless method_defined?(:regular_update)

#
# Assigns a new value to the hash.
#
# Example:
#
# hash = HashWithIndifferentAccess.new
# hash[:key] = "value"
#
def []=(key, value)
regular_writer(convert_key(key), convert_value(value))
end

#
# Updates the instantized hash with values from the second.
#
# Example:
#
# >> hash_1 = HashWithIndifferentAccess.new
# => {}
#
# >> hash_1[:key] = "value"
# => "value"
#
# >> hash_2 = HashWithIndifferentAccess.new
# => {}
#
# >> hash_2[:key] = "New Value!"
# => "New Value!"
#
# >> hash_1.update(hash_2)
# => {"key"=>"New Value!"}
#
def update(other_hash)
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
self
end

alias_method :merge!, :update

# Checks the hash for a key matching the argument passed in
def key?(key)
super(convert_key(key))
end

alias_method :include?, :key?
alias_method :has_key?, :key?
alias_method :member?, :key?

# Fetches the value for the specified key, same as doing hash[key]
def fetch(key, *extras)
super(convert_key(key), *extras)
end

# Returns an array of the values at the specified indicies.
def values_at(*indices)
indices.collect {|key| self[convert_key(key)]}
end

# Returns an exact copy of the hash.
def dup
HashWithIndifferentAccess.new(self)
end

# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
# Does not overwrite the existing hash.
def merge(hash)
self.dup.update(hash)
end

# Removes a specified key from the hash.
def delete(key)
super(convert_key(key))
end

def stringify_keys!; self end
def symbolize_keys!; self end
def to_options!; self end

# Convert to a Hash with String keys.
def to_hash
Hash.new(default).merge(self)
end

protected
def convert_key(key)
key.kind_of?(Symbol) ? key.to_s : key
end

def convert_value(value)
case value
when Hash
value.with_indifferent_access
when Array
value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
else
value
end
end
end

module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module Hash #:nodoc:
module IndifferentAccess #:nodoc:
def with_indifferent_access
hash = HashWithIndifferentAccess.new(self)
hash.default = self.default
hash
end
end
end
end
end
17 changes: 17 additions & 0 deletions lib/merb_support/param_parser.rb
@@ -0,0 +1,17 @@
module Webrat
class ParamParser
def self.parse_query_parameters(query_string)
return {} if query_string.blank?

pairs = query_string.split('&').collect do |chunk|
next if chunk.empty?
key, value = chunk.split('=', 2)
next if key.empty?
value = value.nil? ? nil : CGI.unescape(value)
[ CGI.unescape(key), value ]
end.compact

UrlEncodedPairParser.new(pairs).result
end
end
end

0 comments on commit cdafd2e

Please sign in to comment.