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