ae_page_objects 0.2.0 → 0.3.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.
- data/lib/ae_page_objects.rb +10 -15
- data/lib/ae_page_objects/concerns/load_ensuring.rb +1 -2
- data/lib/ae_page_objects/concerns/staleable.rb +1 -2
- data/lib/ae_page_objects/concerns/visitable.rb +5 -2
- data/lib/ae_page_objects/core/application.rb +18 -5
- data/lib/ae_page_objects/core/dsl.rb +195 -0
- data/lib/ae_page_objects/core/rake_router.rb +5 -5
- data/lib/ae_page_objects/core/universe.rb +5 -5
- data/lib/ae_page_objects/core_ext/module.rb +34 -0
- data/lib/ae_page_objects/element.rb +11 -4
- data/lib/ae_page_objects/element_proxy.rb +3 -2
- data/lib/ae_page_objects/elements/collection.rb +8 -1
- data/lib/ae_page_objects/node.rb +33 -29
- data/lib/ae_page_objects/util/hash_symbolizer.rb +16 -0
- data/lib/ae_page_objects/util/inflector.rb +48 -0
- data/lib/ae_page_objects/{core → util}/internal_helpers.rb +0 -0
- data/lib/ae_page_objects/util/singleton.rb +21 -0
- data/lib/ae_page_objects/version.rb +1 -1
- metadata +20 -34
- data/lib/ae_page_objects/core/dsl/collection.rb +0 -141
- data/lib/ae_page_objects/core/dsl/element.rb +0 -47
- data/lib/ae_page_objects/core/dsl/form_for.rb +0 -30
- data/lib/ae_page_objects/core/singleton.rb +0 -25
data/lib/ae_page_objects.rb
CHANGED
@@ -1,28 +1,20 @@
|
|
1
1
|
require 'capybara'
|
2
2
|
require 'capybara/dsl'
|
3
|
-
require 'active_support'
|
4
|
-
require 'active_support/core_ext/module/delegation'
|
5
|
-
require 'active_support/core_ext/hash/keys'
|
6
|
-
require 'active_support/core_ext/object/try'
|
7
|
-
require 'active_support/core_ext/class'
|
8
|
-
require 'active_support/core_ext/module/introspection'
|
9
3
|
|
10
4
|
require 'ae_page_objects/version'
|
11
5
|
|
12
6
|
module AePageObjects
|
13
7
|
autoload :Universe, 'ae_page_objects/core/universe'
|
14
|
-
autoload :Singleton, 'ae_page_objects/core/singleton'
|
15
8
|
autoload :Application, 'ae_page_objects/core/application'
|
16
9
|
autoload :ApplicationRouter, 'ae_page_objects/core/application_router'
|
17
10
|
autoload :RakeRouter, 'ae_page_objects/core/rake_router'
|
18
|
-
autoload :
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
11
|
+
autoload :Dsl, 'ae_page_objects/core/dsl'
|
12
|
+
|
13
|
+
autoload :Singleton, 'ae_page_objects/util/singleton'
|
14
|
+
autoload :InternalHelpers, 'ae_page_objects/util/internal_helpers'
|
15
|
+
autoload :HashSymbolizer, 'ae_page_objects/util/hash_symbolizer'
|
16
|
+
autoload :Inflector, 'ae_page_objects/util/inflector'
|
17
|
+
|
26
18
|
module Concerns
|
27
19
|
autoload :LoadEnsuring, 'ae_page_objects/concerns/load_ensuring'
|
28
20
|
autoload :Staleable, 'ae_page_objects/concerns/staleable'
|
@@ -40,6 +32,9 @@ module AePageObjects
|
|
40
32
|
autoload :Checkbox, 'ae_page_objects/elements/checkbox'
|
41
33
|
end
|
42
34
|
|
35
|
+
require 'ae_page_objects/core_ext/module'
|
36
|
+
|
37
|
+
|
43
38
|
|
44
39
|
|
45
40
|
|
@@ -1,11 +1,17 @@
|
|
1
1
|
module AePageObjects
|
2
2
|
class Application
|
3
|
-
|
3
|
+
extend AePageObjects::Singleton
|
4
4
|
|
5
5
|
class << self
|
6
6
|
private :new
|
7
7
|
|
8
|
-
|
8
|
+
def initialize!
|
9
|
+
instance.initialize!
|
10
|
+
end
|
11
|
+
|
12
|
+
def router=(router)
|
13
|
+
instance.router = router
|
14
|
+
end
|
9
15
|
|
10
16
|
def inherited(application_class)
|
11
17
|
super
|
@@ -33,10 +39,17 @@ module AePageObjects
|
|
33
39
|
|
34
40
|
attr_writer :router
|
35
41
|
|
36
|
-
|
42
|
+
def universe
|
43
|
+
self.class.universe
|
44
|
+
end
|
37
45
|
|
38
|
-
|
39
|
-
|
46
|
+
def path_recognizes_url?(*args)
|
47
|
+
self.router.path_recognizes_url?(*args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def generate_path(*args)
|
51
|
+
self.router.generate_path(*args)
|
52
|
+
end
|
40
53
|
|
41
54
|
def router
|
42
55
|
@router ||= ApplicationRouter.new
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module AePageObjects
|
2
|
+
module Dsl
|
3
|
+
include InternalHelpers
|
4
|
+
|
5
|
+
def inherited(subclass)
|
6
|
+
subclass.class_eval do
|
7
|
+
class << self
|
8
|
+
def element_attributes
|
9
|
+
@element_attributes ||= {}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def element(name, options = {}, &block)
|
16
|
+
options = options.dup
|
17
|
+
options[:name] ||= name
|
18
|
+
|
19
|
+
klass = field_klass(options, &block)
|
20
|
+
|
21
|
+
self.element_attributes[name.to_sym] = klass
|
22
|
+
|
23
|
+
define_method name do |&block|
|
24
|
+
ElementProxy.new(klass, self, options, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
klass
|
28
|
+
end
|
29
|
+
|
30
|
+
# Defines a collection of elements. Blocks are evaluated on the item class used by the
|
31
|
+
# collection. collection() defines a method on the class that returns an instance of a collection
|
32
|
+
# class which contains instances of the collection's item class.
|
33
|
+
#
|
34
|
+
# Supported signatures are described below.
|
35
|
+
#
|
36
|
+
# ------------------------------------------------
|
37
|
+
# Signature: (no :is, no :contains, no block)
|
38
|
+
#
|
39
|
+
# collection :addresses
|
40
|
+
#
|
41
|
+
# Collection class: ::AePageObjects::Collection
|
42
|
+
# Item class: ::AePageObjects::Element
|
43
|
+
#
|
44
|
+
# ------------------------------------------------
|
45
|
+
# Signature: (no :is, no :contains, block)
|
46
|
+
#
|
47
|
+
# collection :addresses do
|
48
|
+
# element :city
|
49
|
+
# element :state
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# Collection class: one-off subclass of ::AePageObjects::Collection
|
53
|
+
# Item class: one-off subclass of ::AePageObjects::Element
|
54
|
+
# Methods defined on item class:
|
55
|
+
# city() # -> instance of ::AePageObjects::Element
|
56
|
+
# state() # -> instance of ::AePageObjects::Element
|
57
|
+
#
|
58
|
+
# ------------------------------------------------
|
59
|
+
# Signature: (no :is, :contains, no block)
|
60
|
+
#
|
61
|
+
# collection :addresses, :contains => Address
|
62
|
+
#
|
63
|
+
# Collection class: one-off subclass of ::AePageObjects::Collection
|
64
|
+
# Item class: Address
|
65
|
+
#
|
66
|
+
# ------------------------------------------------
|
67
|
+
# Signature: (no :is, :contains, block)
|
68
|
+
#
|
69
|
+
# collection :addresses, :contains => Address do
|
70
|
+
# element :longitude
|
71
|
+
# element :latitude
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# Collection class: one-off subclass of ::AePageObjects::Collection element
|
75
|
+
# Item class: one-off subclass of Address
|
76
|
+
# Methods defined on item class:
|
77
|
+
# longitude() # -> instance of ::AePageObjects::Element
|
78
|
+
# latitude() # -> instance of ::AePageObjects::Element
|
79
|
+
#
|
80
|
+
# ------------------------------------------------
|
81
|
+
# Signature: (:is, no :contains, no block)
|
82
|
+
#
|
83
|
+
# collection :addresses, :is => AddressList
|
84
|
+
#
|
85
|
+
# Collection class: AddressList
|
86
|
+
# Item class: AddressList.item_class
|
87
|
+
#
|
88
|
+
# ------------------------------------------------
|
89
|
+
# Signature: (:is, no :contains, block)
|
90
|
+
#
|
91
|
+
# collection :addresses, :is => AddressList do
|
92
|
+
# element :longitude
|
93
|
+
# element :latitude
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# Collection class: one-off subclass of AddressList
|
97
|
+
# Item class: one-off subclass of AddressList.item_class
|
98
|
+
# Methods defined on item class:
|
99
|
+
# longitude() # -> instance of ::AePageObjects::Element
|
100
|
+
# latitude() # -> instance of ::AePageObjects::Element
|
101
|
+
#
|
102
|
+
# ------------------------------------------------
|
103
|
+
# Signature: (:is, :contains, no block)
|
104
|
+
#
|
105
|
+
# collection :addresses, :is => AddressList, :contains => ExtendedAddress
|
106
|
+
#
|
107
|
+
# Collection class: one-off subclass ofAddressList
|
108
|
+
# Item class: ExtendedAddress
|
109
|
+
#
|
110
|
+
# ------------------------------------------------
|
111
|
+
# Signature: (:is, :contains, block)
|
112
|
+
#
|
113
|
+
# collection :addresses, :is => AddressList, :contains => Address do
|
114
|
+
# element :longitude
|
115
|
+
# element :latitude
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# Collection class: one-off subclass of AddressList
|
119
|
+
# Item class: one-off subclass of Address
|
120
|
+
# Methods defined on item class:
|
121
|
+
# longitude() # -> instance of ::AePageObjects::Element
|
122
|
+
# latitude() # -> instance of ::AePageObjects::Element
|
123
|
+
#
|
124
|
+
def collection(name, options = {}, &block)
|
125
|
+
options ||= {}
|
126
|
+
|
127
|
+
# only a collection class is specified or the item class
|
128
|
+
# specified matches the collection's item class
|
129
|
+
if ! block_given? && options[:is] && (
|
130
|
+
options[:contains].nil? || options[:is].item_class == options[:contains]
|
131
|
+
)
|
132
|
+
return element(name, options)
|
133
|
+
end
|
134
|
+
|
135
|
+
options = options.dup
|
136
|
+
|
137
|
+
# create/get the collection class
|
138
|
+
if options[:is]
|
139
|
+
ensure_class_for_param!(:is, options[:is], ::AePageObjects::Collection)
|
140
|
+
else
|
141
|
+
options[:is] = ::AePageObjects::Collection
|
142
|
+
end
|
143
|
+
|
144
|
+
item_class = options.delete(:contains) || options[:is].item_class
|
145
|
+
if block_given?
|
146
|
+
item_class = item_class.new_subclass(&block).tap do |new_item_class|
|
147
|
+
new_item_class.element_attributes.merge!(item_class.element_attributes)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# since we are creating a new item class, we need to subclass the collection class
|
152
|
+
# so we can parameterize the collection class with an item class
|
153
|
+
options[:is] = options[:is].new_subclass
|
154
|
+
options[:is].item_class = item_class
|
155
|
+
|
156
|
+
element(name, options)
|
157
|
+
end
|
158
|
+
|
159
|
+
def form_for(form_name, options = {}, &block)
|
160
|
+
options ||= {}
|
161
|
+
|
162
|
+
raise ArgumentError, ":is option not supported" if options[:is]
|
163
|
+
raise ArgumentError, "Block required." if block.nil?
|
164
|
+
|
165
|
+
klass = ::AePageObjects::Form.new_subclass(&block)
|
166
|
+
|
167
|
+
options = options.dup
|
168
|
+
options[:is] = klass
|
169
|
+
|
170
|
+
element(form_name, options)
|
171
|
+
|
172
|
+
klass.element_attributes.each do |element_name, element_klazz|
|
173
|
+
class_eval <<-RUBY
|
174
|
+
def #{element_name}(*args, &block)
|
175
|
+
#{form_name}.#{element_name}(*args, &block)
|
176
|
+
end
|
177
|
+
RUBY
|
178
|
+
|
179
|
+
self.element_attributes[element_name] = element_klazz
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def field_klass(options, &block)
|
186
|
+
klass = options.delete(:is) || ::AePageObjects::Element
|
187
|
+
|
188
|
+
if block_given?
|
189
|
+
klass.new_subclass(&block)
|
190
|
+
else
|
191
|
+
klass
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -5,7 +5,7 @@ module AePageObjects
|
|
5
5
|
|
6
6
|
def initialize(rake_routes, mounted_prefix = '')
|
7
7
|
@mounted_prefix = mounted_prefix || ""
|
8
|
-
@routes =
|
8
|
+
@routes = {}
|
9
9
|
route_line_regex = /(\w+)(?:\s[A-Z]+)?\s+(\/.*)\(.:format\).*$/
|
10
10
|
|
11
11
|
rake_routes.split("\n").each do |line|
|
@@ -32,11 +32,11 @@ module AePageObjects
|
|
32
32
|
end
|
33
33
|
|
34
34
|
if route = @routes[named_route]
|
35
|
-
options = args.
|
35
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
36
36
|
route.generate_path(options)
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
private
|
41
41
|
|
42
42
|
class Path < String
|
@@ -50,7 +50,7 @@ module AePageObjects
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def generate(param_values)
|
53
|
-
param_values = param_values.symbolize_keys
|
53
|
+
param_values = HashSymbolizer.new(param_values).symbolize_keys
|
54
54
|
@params.values.inject(self) do |path, param|
|
55
55
|
param.substitute(path, param_values)
|
56
56
|
end
|
@@ -142,7 +142,7 @@ module AePageObjects
|
|
142
142
|
end
|
143
143
|
|
144
144
|
def generate_path(options)
|
145
|
-
options = options.symbolize_keys
|
145
|
+
options = HashSymbolizer.new(options).symbolize_keys
|
146
146
|
@path.generate(options)
|
147
147
|
end
|
148
148
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module AePageObjects
|
2
2
|
module Universe
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
def self.included(target)
|
4
|
+
target.class_eval do
|
5
|
+
class << self
|
6
|
+
attr_accessor :page_objects_application_class
|
7
|
+
end
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# lifted from activesupport
|
2
|
+
|
3
|
+
class Module
|
4
|
+
|
5
|
+
# Returns the name of the module containing this one.
|
6
|
+
#
|
7
|
+
# M::N.parent_name # => "M"
|
8
|
+
def parent_name
|
9
|
+
unless defined? @parent_name
|
10
|
+
@parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
|
11
|
+
end
|
12
|
+
@parent_name
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the module which contains this one according to its name.
|
16
|
+
#
|
17
|
+
# module M
|
18
|
+
# module N
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# X = M::N
|
22
|
+
#
|
23
|
+
# M::N.parent # => M
|
24
|
+
# X.parent # => M
|
25
|
+
#
|
26
|
+
# The parent of top-level and anonymous modules is Object.
|
27
|
+
#
|
28
|
+
# M.parent # => Object
|
29
|
+
# Module.new.parent # => Object
|
30
|
+
#
|
31
|
+
def parent
|
32
|
+
parent_name ? AePageObjects::Inflector.constantize(parent_name) : Object
|
33
|
+
end
|
34
|
+
end
|
@@ -38,7 +38,12 @@ module AePageObjects
|
|
38
38
|
|
39
39
|
def __full_name__
|
40
40
|
if parent.respond_to?(:__full_name__)
|
41
|
-
[ parent.__full_name__, __name__ ].compact
|
41
|
+
name_parts = [ parent.__full_name__, __name__ ].compact
|
42
|
+
if name_parts.empty?
|
43
|
+
nil
|
44
|
+
else
|
45
|
+
name_parts.join('_')
|
46
|
+
end
|
42
47
|
else
|
43
48
|
__name__
|
44
49
|
end
|
@@ -70,12 +75,14 @@ module AePageObjects
|
|
70
75
|
|
71
76
|
def configure(options)
|
72
77
|
@locator = options.delete(:locator)
|
73
|
-
@name = options.delete(:name)
|
78
|
+
@name = options.delete(:name)
|
79
|
+
|
80
|
+
@name = @name.to_s if @name
|
74
81
|
end
|
75
82
|
|
76
83
|
def parse_options(options_or_locator)
|
77
84
|
if options_or_locator.is_a?( Hash )
|
78
|
-
options_or_locator.symbolize_keys
|
85
|
+
HashSymbolizer.new(options_or_locator).symbolize_keys
|
79
86
|
else
|
80
87
|
{:locator => options_or_locator}
|
81
88
|
end
|
@@ -88,7 +95,7 @@ module AePageObjects
|
|
88
95
|
def scoped_node
|
89
96
|
if @locator
|
90
97
|
locator = eval_locator(@locator)
|
91
|
-
if locator.
|
98
|
+
if ! locator.empty?
|
92
99
|
return parent.find(*locator)
|
93
100
|
end
|
94
101
|
end
|
@@ -27,7 +27,8 @@ module AePageObjects
|
|
27
27
|
# Provided so that visible? can be asked without
|
28
28
|
# an explicit check for present? first.
|
29
29
|
def visible?
|
30
|
-
|
30
|
+
inst = presence
|
31
|
+
! inst.nil? && inst.visible?
|
31
32
|
end
|
32
33
|
|
33
34
|
def not_visible?
|
@@ -41,7 +42,7 @@ module AePageObjects
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def present?
|
44
|
-
presence.
|
45
|
+
! presence.nil?
|
45
46
|
end
|
46
47
|
|
47
48
|
def not_present?
|
@@ -1,8 +1,15 @@
|
|
1
1
|
module AePageObjects
|
2
2
|
class Collection < Element
|
3
|
-
|
3
|
+
class << self
|
4
|
+
attr_accessor :item_class
|
5
|
+
end
|
6
|
+
|
4
7
|
self.item_class = Element
|
5
8
|
|
9
|
+
def item_class
|
10
|
+
self.class.item_class
|
11
|
+
end
|
12
|
+
|
6
13
|
def at(index, &block)
|
7
14
|
if index >= size || index < 0
|
8
15
|
nil
|
data/lib/ae_page_objects/node.rb
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
module AePageObjects
|
2
2
|
class Node
|
3
3
|
module Methods
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
include Dsl::Element
|
7
|
-
include Dsl::Collection
|
8
|
-
include Dsl::FormFor
|
9
|
-
|
10
4
|
def initialize(capybara_node = Capybara.current_session)
|
11
5
|
@node = capybara_node
|
12
6
|
end
|
@@ -19,20 +13,27 @@ module AePageObjects
|
|
19
13
|
raise "Must implement!"
|
20
14
|
end
|
21
15
|
|
22
|
-
|
23
|
-
|
16
|
+
def current_url
|
17
|
+
self.class.current_url
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_url_without_params
|
21
|
+
self.class.current_url_without_params
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
METHODS_TO_DELEGATE_TO_NODE = [:find, :all, :value, :set, :text, :visible?]
|
25
|
+
METHODS_TO_DELEGATE_TO_NODE.each do |m|
|
26
|
+
class_eval <<-RUBY
|
27
|
+
def #{m}(*args, &block)
|
28
|
+
node.send(:#{m}, *args, &block)
|
29
|
+
end
|
30
|
+
RUBY
|
31
|
+
end
|
31
32
|
|
32
33
|
private
|
33
34
|
|
34
35
|
def eval_locator(locator)
|
35
|
-
return unless locator
|
36
|
+
return [] unless locator
|
36
37
|
|
37
38
|
if locator.respond_to?(:call)
|
38
39
|
locator = instance_eval(&locator)
|
@@ -40,26 +41,29 @@ module AePageObjects
|
|
40
41
|
|
41
42
|
locator.is_a?(Array) ? locator : [locator.to_s]
|
42
43
|
end
|
44
|
+
end
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
46
|
+
module ClassMethods
|
47
|
+
def current_url
|
48
|
+
Capybara.current_session.current_url.sub(/^https?:\/\/[^\/]*/, '')
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
def current_url_without_params
|
52
|
+
current_url.sub(/\?.*/, '')
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
55
|
+
def new_subclass(&block)
|
56
|
+
klass = Class.new(self)
|
57
|
+
klass.class_eval(&block) if block
|
58
|
+
klass
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
|
+
extend Dsl
|
63
|
+
|
62
64
|
include Methods
|
65
|
+
extend ClassMethods
|
66
|
+
|
63
67
|
include Concerns::LoadEnsuring
|
64
68
|
include Concerns::Staleable
|
65
69
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AePageObjects
|
2
|
+
class HashSymbolizer
|
3
|
+
|
4
|
+
def initialize(hash)
|
5
|
+
@hash = hash
|
6
|
+
end
|
7
|
+
|
8
|
+
def symbolize_keys
|
9
|
+
@hash.dup.tap do |hash|
|
10
|
+
hash.keys.each do |key|
|
11
|
+
hash[(key.to_sym rescue key) || key] = hash.delete(key)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module AePageObjects
|
2
|
+
module Inflector
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# Ruby 1.9 introduces an inherit argument for Module#const_get and
|
6
|
+
# #const_defined? and changes their default behavior.
|
7
|
+
if Module.method(:const_get).arity == 1
|
8
|
+
# Tries to find a constant with the name specified in the argument string:
|
9
|
+
#
|
10
|
+
# "Module".constantize # => Module
|
11
|
+
# "Test::Unit".constantize # => Test::Unit
|
12
|
+
#
|
13
|
+
# The name is assumed to be the one of a top-level constant, no matter whether
|
14
|
+
# it starts with "::" or not. No lexical context is taken into account:
|
15
|
+
#
|
16
|
+
# C = 'outside'
|
17
|
+
# module M
|
18
|
+
# C = 'inside'
|
19
|
+
# C # => 'inside'
|
20
|
+
# "C".constantize # => 'outside', same as ::C
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# NameError is raised when the name is not in CamelCase or the constant is
|
24
|
+
# unknown.
|
25
|
+
def constantize(camel_cased_word)
|
26
|
+
names = camel_cased_word.split('::')
|
27
|
+
names.shift if names.empty? || names.first.empty?
|
28
|
+
|
29
|
+
constant = Object
|
30
|
+
names.each do |name|
|
31
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
32
|
+
end
|
33
|
+
constant
|
34
|
+
end
|
35
|
+
else
|
36
|
+
def constantize(camel_cased_word) #:nodoc:
|
37
|
+
names = camel_cased_word.split('::')
|
38
|
+
names.shift if names.empty? || names.first.empty?
|
39
|
+
|
40
|
+
constant = Object
|
41
|
+
names.each do |name|
|
42
|
+
constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
|
43
|
+
end
|
44
|
+
constant
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AePageObjects
|
2
|
+
module Singleton
|
3
|
+
def instance
|
4
|
+
@instance ||= new
|
5
|
+
end
|
6
|
+
|
7
|
+
def respond_to?(*args)
|
8
|
+
super || instance.respond_to?(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def configure(&block)
|
12
|
+
class_eval(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def method_missing(*args, &block)
|
18
|
+
instance.send(*args, &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ae_page_objects
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Donnie Tognazzini
|
@@ -15,27 +15,12 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2013-07-
|
18
|
+
date: 2013-07-08 00:00:00 Z
|
19
19
|
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
21
|
-
type: :runtime
|
22
|
-
name: activesupport
|
23
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
|
-
none: false
|
25
|
-
requirements:
|
26
|
-
- - ~>
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
hash: 7
|
29
|
-
segments:
|
30
|
-
- 3
|
31
|
-
- 0
|
32
|
-
version: "3.0"
|
33
|
-
requirement: *id001
|
34
|
-
prerelease: false
|
35
20
|
- !ruby/object:Gem::Dependency
|
36
21
|
type: :runtime
|
37
22
|
name: capybara
|
38
|
-
version_requirements: &
|
23
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
39
24
|
none: false
|
40
25
|
requirements:
|
41
26
|
- - ~>
|
@@ -45,12 +30,12 @@ dependencies:
|
|
45
30
|
- 1
|
46
31
|
- 1
|
47
32
|
version: "1.1"
|
48
|
-
requirement: *
|
33
|
+
requirement: *id001
|
49
34
|
prerelease: false
|
50
35
|
- !ruby/object:Gem::Dependency
|
51
36
|
type: :runtime
|
52
37
|
name: nokogiri
|
53
|
-
version_requirements: &
|
38
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
54
39
|
none: false
|
55
40
|
requirements:
|
56
41
|
- - ~>
|
@@ -61,12 +46,12 @@ dependencies:
|
|
61
46
|
- 5
|
62
47
|
- 9
|
63
48
|
version: 1.5.9
|
64
|
-
requirement: *
|
49
|
+
requirement: *id002
|
65
50
|
prerelease: false
|
66
51
|
- !ruby/object:Gem::Dependency
|
67
52
|
type: :development
|
68
53
|
name: appraisal
|
69
|
-
version_requirements: &
|
54
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
70
55
|
none: false
|
71
56
|
requirements:
|
72
57
|
- - ~>
|
@@ -77,12 +62,12 @@ dependencies:
|
|
77
62
|
- 5
|
78
63
|
- 1
|
79
64
|
version: 0.5.1
|
80
|
-
requirement: *
|
65
|
+
requirement: *id003
|
81
66
|
prerelease: false
|
82
67
|
- !ruby/object:Gem::Dependency
|
83
68
|
type: :development
|
84
69
|
name: mocha
|
85
|
-
version_requirements: &
|
70
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
86
71
|
none: false
|
87
72
|
requirements:
|
88
73
|
- - "="
|
@@ -93,12 +78,12 @@ dependencies:
|
|
93
78
|
- 13
|
94
79
|
- 3
|
95
80
|
version: 0.13.3
|
96
|
-
requirement: *
|
81
|
+
requirement: *id004
|
97
82
|
prerelease: false
|
98
83
|
- !ruby/object:Gem::Dependency
|
99
84
|
type: :development
|
100
85
|
name: selenium-webdriver
|
101
|
-
version_requirements: &
|
86
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
102
87
|
none: false
|
103
88
|
requirements:
|
104
89
|
- - ">="
|
@@ -107,7 +92,7 @@ dependencies:
|
|
107
92
|
segments:
|
108
93
|
- 0
|
109
94
|
version: "0"
|
110
|
-
requirement: *
|
95
|
+
requirement: *id005
|
111
96
|
prerelease: false
|
112
97
|
description: Capybara Page Objects pattern
|
113
98
|
email:
|
@@ -125,13 +110,10 @@ files:
|
|
125
110
|
- lib/ae_page_objects/concerns/visitable.rb
|
126
111
|
- lib/ae_page_objects/core/application.rb
|
127
112
|
- lib/ae_page_objects/core/application_router.rb
|
128
|
-
- lib/ae_page_objects/core/dsl
|
129
|
-
- lib/ae_page_objects/core/dsl/element.rb
|
130
|
-
- lib/ae_page_objects/core/dsl/form_for.rb
|
131
|
-
- lib/ae_page_objects/core/internal_helpers.rb
|
113
|
+
- lib/ae_page_objects/core/dsl.rb
|
132
114
|
- lib/ae_page_objects/core/rake_router.rb
|
133
|
-
- lib/ae_page_objects/core/singleton.rb
|
134
115
|
- lib/ae_page_objects/core/universe.rb
|
116
|
+
- lib/ae_page_objects/core_ext/module.rb
|
135
117
|
- lib/ae_page_objects/document.rb
|
136
118
|
- lib/ae_page_objects/element.rb
|
137
119
|
- lib/ae_page_objects/element_proxy.rb
|
@@ -140,6 +122,10 @@ files:
|
|
140
122
|
- lib/ae_page_objects/elements/form.rb
|
141
123
|
- lib/ae_page_objects/elements/select.rb
|
142
124
|
- lib/ae_page_objects/node.rb
|
125
|
+
- lib/ae_page_objects/util/hash_symbolizer.rb
|
126
|
+
- lib/ae_page_objects/util/inflector.rb
|
127
|
+
- lib/ae_page_objects/util/internal_helpers.rb
|
128
|
+
- lib/ae_page_objects/util/singleton.rb
|
143
129
|
- lib/ae_page_objects/version.rb
|
144
130
|
homepage: http://github.com/appfolio/ae_page_objects
|
145
131
|
licenses:
|
@@ -1,141 +0,0 @@
|
|
1
|
-
module AePageObjects
|
2
|
-
module Dsl
|
3
|
-
module Collection
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
include Dsl::Element
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
include InternalHelpers
|
9
|
-
|
10
|
-
# Defines a collection of elements. Blocks are evaluated on the item class used by the
|
11
|
-
# collection. collection() defines a method on the class that returns an instance of a collection
|
12
|
-
# class which contains instances of the collection's item class.
|
13
|
-
#
|
14
|
-
# Supported signatures are described below.
|
15
|
-
#
|
16
|
-
# ------------------------------------------------
|
17
|
-
# Signature: (no :is, no :contains, no block)
|
18
|
-
#
|
19
|
-
# collection :addresses
|
20
|
-
#
|
21
|
-
# Collection class: ::AePageObjects::Collection
|
22
|
-
# Item class: ::AePageObjects::Element
|
23
|
-
#
|
24
|
-
# ------------------------------------------------
|
25
|
-
# Signature: (no :is, no :contains, block)
|
26
|
-
#
|
27
|
-
# collection :addresses do
|
28
|
-
# element :city
|
29
|
-
# element :state
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# Collection class: one-off subclass of ::AePageObjects::Collection
|
33
|
-
# Item class: one-off subclass of ::AePageObjects::Element
|
34
|
-
# Methods defined on item class:
|
35
|
-
# city() # -> instance of ::AePageObjects::Element
|
36
|
-
# state() # -> instance of ::AePageObjects::Element
|
37
|
-
#
|
38
|
-
# ------------------------------------------------
|
39
|
-
# Signature: (no :is, :contains, no block)
|
40
|
-
#
|
41
|
-
# collection :addresses, :contains => Address
|
42
|
-
#
|
43
|
-
# Collection class: one-off subclass of ::AePageObjects::Collection
|
44
|
-
# Item class: Address
|
45
|
-
#
|
46
|
-
# ------------------------------------------------
|
47
|
-
# Signature: (no :is, :contains, block)
|
48
|
-
#
|
49
|
-
# collection :addresses, :contains => Address do
|
50
|
-
# element :longitude
|
51
|
-
# element :latitude
|
52
|
-
# end
|
53
|
-
#
|
54
|
-
# Collection class: one-off subclass of ::AePageObjects::Collection element
|
55
|
-
# Item class: one-off subclass of Address
|
56
|
-
# Methods defined on item class:
|
57
|
-
# longitude() # -> instance of ::AePageObjects::Element
|
58
|
-
# latitude() # -> instance of ::AePageObjects::Element
|
59
|
-
#
|
60
|
-
# ------------------------------------------------
|
61
|
-
# Signature: (:is, no :contains, no block)
|
62
|
-
#
|
63
|
-
# collection :addresses, :is => AddressList
|
64
|
-
#
|
65
|
-
# Collection class: AddressList
|
66
|
-
# Item class: AddressList.item_class
|
67
|
-
#
|
68
|
-
# ------------------------------------------------
|
69
|
-
# Signature: (:is, no :contains, block)
|
70
|
-
#
|
71
|
-
# collection :addresses, :is => AddressList do
|
72
|
-
# element :longitude
|
73
|
-
# element :latitude
|
74
|
-
# end
|
75
|
-
#
|
76
|
-
# Collection class: one-off subclass of AddressList
|
77
|
-
# Item class: one-off subclass of AddressList.item_class
|
78
|
-
# Methods defined on item class:
|
79
|
-
# longitude() # -> instance of ::AePageObjects::Element
|
80
|
-
# latitude() # -> instance of ::AePageObjects::Element
|
81
|
-
#
|
82
|
-
# ------------------------------------------------
|
83
|
-
# Signature: (:is, :contains, no block)
|
84
|
-
#
|
85
|
-
# collection :addresses, :is => AddressList, :contains => ExtendedAddress
|
86
|
-
#
|
87
|
-
# Collection class: one-off subclass ofAddressList
|
88
|
-
# Item class: ExtendedAddress
|
89
|
-
#
|
90
|
-
# ------------------------------------------------
|
91
|
-
# Signature: (:is, :contains, block)
|
92
|
-
#
|
93
|
-
# collection :addresses, :is => AddressList, :contains => Address do
|
94
|
-
# element :longitude
|
95
|
-
# element :latitude
|
96
|
-
# end
|
97
|
-
#
|
98
|
-
# Collection class: one-off subclass of AddressList
|
99
|
-
# Item class: one-off subclass of Address
|
100
|
-
# Methods defined on item class:
|
101
|
-
# longitude() # -> instance of ::AePageObjects::Element
|
102
|
-
# latitude() # -> instance of ::AePageObjects::Element
|
103
|
-
#
|
104
|
-
def collection(name, options = {}, &block)
|
105
|
-
options ||= {}
|
106
|
-
|
107
|
-
# only a collection class is specified or the item class
|
108
|
-
# specified matches the collection's item class
|
109
|
-
if block.blank? && options[:is] && (
|
110
|
-
options[:contains].blank? || options[:is].item_class == options[:contains]
|
111
|
-
)
|
112
|
-
return element(name, options)
|
113
|
-
end
|
114
|
-
|
115
|
-
options = options.dup
|
116
|
-
|
117
|
-
# create/get the collection class
|
118
|
-
if options[:is]
|
119
|
-
ensure_class_for_param!(:is, options[:is], ::AePageObjects::Collection)
|
120
|
-
else
|
121
|
-
options[:is] = ::AePageObjects::Collection
|
122
|
-
end
|
123
|
-
|
124
|
-
item_class = options.delete(:contains) || options[:is].item_class
|
125
|
-
if block.present?
|
126
|
-
item_class = item_class.new_subclass(&block).tap do |new_item_class|
|
127
|
-
new_item_class.element_attributes.merge!(item_class.element_attributes)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
# since we are creating a new item class, we need to subclass the collection class
|
132
|
-
# so we can parameterize the collection class with an item class
|
133
|
-
options[:is] = options[:is].new_subclass
|
134
|
-
options[:is].item_class = item_class
|
135
|
-
|
136
|
-
element(name, options)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module AePageObjects
|
2
|
-
module Dsl
|
3
|
-
module Element
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
|
8
|
-
def inherited(subclass)
|
9
|
-
subclass.class_eval do
|
10
|
-
class << self
|
11
|
-
def element_attributes
|
12
|
-
@element_attributes ||= {}
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def element(name, options = {}, &block)
|
19
|
-
options = options.dup
|
20
|
-
options[:name] ||= name
|
21
|
-
|
22
|
-
klass = field_klass(options, &block)
|
23
|
-
|
24
|
-
self.element_attributes[name.to_sym] = klass
|
25
|
-
|
26
|
-
define_method name do |&block|
|
27
|
-
ElementProxy.new(klass, self, options, &block)
|
28
|
-
end
|
29
|
-
|
30
|
-
klass
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def field_klass(options, &block)
|
36
|
-
klass = options.delete(:is) || ::AePageObjects::Element
|
37
|
-
|
38
|
-
if block_given?
|
39
|
-
klass.new_subclass(&block)
|
40
|
-
else
|
41
|
-
klass
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module AePageObjects
|
2
|
-
module Dsl
|
3
|
-
module FormFor
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
include Dsl::Element
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
|
9
|
-
def form_for(form_name, options = {}, &block)
|
10
|
-
options ||= {}
|
11
|
-
|
12
|
-
raise ArgumentError, ":is option not supported" if options[:is]
|
13
|
-
raise ArgumentError, "Block required." unless block.present?
|
14
|
-
|
15
|
-
klass = ::AePageObjects::Form.new_subclass(&block)
|
16
|
-
|
17
|
-
options = options.dup
|
18
|
-
options[:is] = klass
|
19
|
-
|
20
|
-
element(form_name, options)
|
21
|
-
|
22
|
-
klass.element_attributes.each do |element_name, element_klazz|
|
23
|
-
delegate element_name, :to => form_name
|
24
|
-
self.element_attributes[element_name] = element_klazz
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module AePageObjects
|
2
|
-
module Singleton
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
module ClassMethods
|
6
|
-
def instance
|
7
|
-
@instance ||= new
|
8
|
-
end
|
9
|
-
|
10
|
-
def respond_to?(*args)
|
11
|
-
super || instance.respond_to?(*args)
|
12
|
-
end
|
13
|
-
|
14
|
-
def configure(&block)
|
15
|
-
class_eval(&block)
|
16
|
-
end
|
17
|
-
|
18
|
-
protected
|
19
|
-
|
20
|
-
def method_missing(*args, &block)
|
21
|
-
instance.send(*args, &block)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|