Skip to content

Commit

Permalink
Merge pull request #69 from appfolio/fixChangeTo
Browse files Browse the repository at this point in the history
create document_proxy from loaded_page and query, delegate implicit_document class query to query object
  • Loading branch information
dtognazzini committed Sep 24, 2014
2 parents 0ed0c32 + bf86422 commit 8c30e23
Show file tree
Hide file tree
Showing 39 changed files with 375 additions and 342 deletions.
24 changes: 12 additions & 12 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
Copyright (C) 2012 AppFolio, inc.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

2 changes: 1 addition & 1 deletion ae_page_objects.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Gem::Specification.new do |s|
s.require_paths = ["lib"]
s.rubygems_version = "1.8.24"
s.summary = "Capybara Page Objects pattern"

s.files = `git ls-files -- lib`.split("\n")

s.add_dependency('capybara', ['>= 1.1', '< 2.3'])
Expand Down
4 changes: 2 additions & 2 deletions lib/ae_page_objects.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module SingleWindow
end

autoload :Window, 'ae_page_objects/window'

autoload :DocumentQuery, 'ae_page_objects/document_query'
autoload :DocumentLoader, 'ae_page_objects/document_loader'

Expand All @@ -48,7 +48,7 @@ module SingleWindow
autoload :DocumentProxy, 'ae_page_objects/document_proxy'
autoload :Element, 'ae_page_objects/element'
autoload :ElementProxy, 'ae_page_objects/element_proxy'

autoload :Collection, 'ae_page_objects/elements/collection'
autoload :Form, 'ae_page_objects/elements/form'
autoload :Select, 'ae_page_objects/elements/select'
Expand Down
8 changes: 4 additions & 4 deletions lib/ae_page_objects/concerns/load_ensuring.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ def initialize(*args)
super
ensure_loaded!
end

private

def loaded_locator
end

def ensure_loaded!
if locator = loaded_locator
find(*eval_locator(locator))
find(*eval_locator(locator))
end

self
rescue Capybara::ElementNotFound => e
raise LoadingElementFailed, e.message
Expand Down
8 changes: 4 additions & 4 deletions lib/ae_page_objects/concerns/staleable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ def node

super
end

private

def stale!
@stale = true
end

end
end
end
end
16 changes: 8 additions & 8 deletions lib/ae_page_objects/concerns/visitable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def self.included(target)
end

private

def ensure_loaded!
unless Waiter.wait_for { self.class.can_load_from_current_url? }
raise LoadingPageFailed, "#{self.class.name} cannot be loaded with url '#{current_url_without_params}'"
Expand All @@ -19,7 +19,7 @@ def ensure_loaded!
raise LoadingPageFailed, e.message
end
end

module VisitMethod
def visit(*args)
raise ArgumentError, "Cannot pass block to visit()" if block_given?
Expand All @@ -31,9 +31,9 @@ def visit(*args)
new
end
end

module ClassMethods

def can_load_from_current_url?
return true if paths.empty?

Expand All @@ -43,18 +43,18 @@ def can_load_from_current_url?
site.path_recognizes_url?(path, url)
end
end

private

def paths
@paths ||= []
end

def path(path_method)
raise ArgumentError, "path must be a symbol or string" if ! path_method.is_a?(Symbol) && ! path_method.is_a?(String)

paths << path_method

extend VisitMethod
end
end
Expand Down
42 changes: 21 additions & 21 deletions lib/ae_page_objects/core/rake_router.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
module AePageObjects
class RakeRouter < BasicRouter

attr_reader :routes

def initialize(rake_routes, mounted_prefix = '')
@mounted_prefix = mounted_prefix || ""
@routes = {}
route_line_regex = /(\w+)(?:\s[A-Z]+)?\s+(\/.*)\(.:format\).*$/

rake_routes.split("\n").each do |line|
line = line.strip
matches = route_line_regex.match(line)
Expand All @@ -16,7 +16,7 @@ def initialize(rake_routes, mounted_prefix = '')
end
end
end

def path_recognizes_url?(path, url)
if path.is_a?(Symbol)
route = @routes[path]
Expand All @@ -30,25 +30,25 @@ def generate_path(named_route, *args)
if named_route.is_a?(String)
return Path.new(@mounted_prefix + named_route)
end

if route = @routes[named_route]
options = args.last.is_a?(Hash) ? args.pop : {}
route.generate_path(options)
end
end

private

class Path < String
attr_reader :params, :regex

def initialize(value)
super(value.gsub(/(\/)+/, '/').sub(/\(\.\:format\)$/, ''))

@params = parse_params
@regex = generate_regex
end

def generate(param_values)
param_values = HashSymbolizer.new(param_values).symbolize_keys
@params.values.inject(self) do |path, param|
Expand All @@ -61,19 +61,19 @@ def parse_params
# overwrite the required status with the optional
{}.merge(required_params).merge(optional_params)
end

def find_params(using_regex)
scan(using_regex).flatten.map(&:to_sym)
end

def optional_params
{}.tap do |optional_params|
find_params(/\(\/\:(\w+)\)/).each do |param_name|
optional_params[param_name] = Param.new(param_name, true)
end
end
end

def required_params
{}.tap do |required_params|
find_params(/\:(\w+)/).each do |param_name|
Expand All @@ -85,38 +85,38 @@ def required_params
def generate_regex
regex_spec = @params.values.inject(self) do |regex_spec, param|
param.replace_param_in_url(regex_spec)
end
end
Regexp.new regex_spec
end
end

class Param < Struct.new(:name, :optional)
include Comparable

def optional?
optional
end

def <=>(other)
name.to_s <=> other.name.to_s
end

def eql?(other)
name == other.name
end

def hash
name.hash
end

def replace_param_in_url(url)
if optional?
url.gsub("(/:#{name})", '(\/.+)?')
else
url.gsub(":#{name}", '(.+)')
end
end

def substitute(url, values)
if optional?
if values[name]
Expand All @@ -130,13 +130,13 @@ def substitute(url, values)
end
end
end

class Route
def initialize(spec, mounted_prefix)
@path = Path.new(mounted_prefix + spec)
@path.freeze
end

def matches?(url)
url =~ @path.regex
end
Expand Down
10 changes: 1 addition & 9 deletions lib/ae_page_objects/document_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ def initialize(query, strategy)
@strategy = strategy
end

def default_document_class
@default_document_class ||= @query.conditions.first.document_class
end

def permitted_types_dump
@permitted_types_dump ||= @query.conditions.map(&:document_class).map(&:name).inspect
end

def load
Waiter.wait_for do
@query.conditions.each do |document_condition|
Expand All @@ -24,7 +16,7 @@ def load
nil
end

raise @strategy.document_not_loaded_error(self)
raise DocumentLoadError, @strategy.document_not_loaded_error_message(@query)
end
end
end
22 changes: 11 additions & 11 deletions lib/ae_page_objects/document_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ class DocumentProxy
end
end

def initialize(loaded_page, document_loader)
@loaded_page = loaded_page
@document_loader = document_loader
def initialize(loaded_page, query)
@loaded_page = loaded_page
@query = query
end

def is_a?(document_class)
Expand All @@ -23,25 +23,25 @@ def as_a(document_class)
return @loaded_page
end

raise DocumentLoadError, "#{document_class.name} not expected. Allowed types: #{@document_loader.permitted_types_dump}"
raise CastError, "Loaded page is not a #{document_class.name}. Allowed pages: #{@query.permitted_types_dump}"
end

private

def implicit_document
@implicit_document ||= as_a(implicit_document_class)
end

def implicit_document_class
@implicit_document_class ||= @document_loader.default_document_class
if @loaded_page.is_a? @query.default_document_class
@loaded_page
else
raise CastError, "#{@query.default_document_class} expected, but #{@loaded_page.class} loaded"
end
end

def method_missing(name, *args, &block)
implicit_document.__send__(name, *args, &block)
end

def respond_to?(*args)
super || implicit_document_class.allocate.respond_to?(*args)
def respond_to_missing?(*args)
super || implicit_document.respond_to?(*args)
end
end
end
8 changes: 8 additions & 0 deletions lib/ae_page_objects/document_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,13 @@ def initialize(*document_classes, &block)
def matches(document_class, conditions = {}, &block_condition)
@conditions << Condition.new(document_class, conditions, &block_condition)
end

def default_document_class
conditions.first.document_class
end

def permitted_types_dump
conditions.map(&:document_class).map(&:name).inspect
end
end
end
Loading

0 comments on commit 8c30e23

Please sign in to comment.