automation_object 0.6.0 → 0.7.5
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.
- checksums.yaml +4 -4
- data/lib/automation_object/blue_print/hash_adapter/hook_action.rb +1 -1
- data/lib/automation_object/driver/appium_adapter/driver.rb +17 -1
- data/lib/automation_object/driver/driver.rb +7 -1
- data/lib/automation_object/driver/nokogiri_adapter/driver.rb +6 -0
- data/lib/automation_object/driver/selenium_adapter/driver.rb +16 -1
- data/lib/automation_object/dsl/_base.rb +6 -3
- data/lib/automation_object/dsl/_proxy.rb +2 -2
- data/lib/automation_object/dsl/element.rb +9 -3
- data/lib/automation_object/dsl/element_array.rb +9 -3
- data/lib/automation_object/dsl/element_hash.rb +9 -3
- data/lib/automation_object/dsl/modal.rb +9 -6
- data/lib/automation_object/dsl/screen.rb +5 -7
- data/lib/automation_object/dsl/top.rb +7 -3
- data/lib/automation_object/state/_base.rb +72 -0
- data/lib/automation_object/state/_common_element.rb +44 -0
- data/lib/automation_object/state/{error.rb → _error.rb} +4 -0
- data/lib/automation_object/state/element.rb +23 -0
- data/lib/automation_object/state/element_array.rb +26 -0
- data/lib/automation_object/state/element_hash.rb +34 -0
- data/lib/automation_object/state/element_proxy.rb +31 -0
- data/lib/automation_object/state/hook.rb +51 -0
- data/lib/automation_object/state/{composite/hook_action.rb → hook_action.rb} +11 -13
- data/lib/automation_object/state/hook_actions/action_loop.rb +43 -0
- data/lib/automation_object/state/hook_actions/change_screen.rb +23 -0
- data/lib/automation_object/state/hook_actions/change_to_previous_screen.rb +23 -0
- data/lib/automation_object/state/hook_actions/close_modal.rb +21 -0
- data/lib/automation_object/state/hook_actions/close_screen.rb +20 -0
- data/lib/automation_object/state/hook_actions/element_requirement.rb +30 -0
- data/lib/automation_object/state/hook_actions/new_screen.rb +49 -0
- data/lib/automation_object/state/hook_actions/possible_screen_changes.rb +23 -0
- data/lib/automation_object/state/{composite/hook_actions → hook_actions}/reset_screen.rb +4 -5
- data/lib/automation_object/state/hook_actions/show_modal.rb +18 -0
- data/lib/automation_object/state/hook_actions/sleep.rb +13 -0
- data/lib/automation_object/state/hook_actions/wait_for_elements.rb +18 -0
- data/lib/automation_object/state/modal.rb +47 -0
- data/lib/automation_object/state/screen.rb +70 -0
- data/lib/automation_object/state/top.rb +43 -0
- data/lib/automation_object/state.rb +3 -3
- data/lib/automation_object/version.rb +1 -1
- metadata +40 -43
- data/lib/automation_object/state/composite/_base.rb +0 -81
- data/lib/automation_object/state/composite/_common_element.rb +0 -38
- data/lib/automation_object/state/composite/element.rb +0 -24
- data/lib/automation_object/state/composite/element_array.rb +0 -27
- data/lib/automation_object/state/composite/element_hash.rb +0 -35
- data/lib/automation_object/state/composite/element_proxy.rb +0 -33
- data/lib/automation_object/state/composite/helpers/window.rb +0 -79
- data/lib/automation_object/state/composite/helpers/window_manager.rb +0 -59
- data/lib/automation_object/state/composite/hook.rb +0 -55
- data/lib/automation_object/state/composite/hook_actions/action_loop.rb +0 -45
- data/lib/automation_object/state/composite/hook_actions/change_screen.rb +0 -23
- data/lib/automation_object/state/composite/hook_actions/change_to_previous_screen.rb +0 -23
- data/lib/automation_object/state/composite/hook_actions/close_modal.rb +0 -29
- data/lib/automation_object/state/composite/hook_actions/close_screen.rb +0 -19
- data/lib/automation_object/state/composite/hook_actions/element_requirement.rb +0 -32
- data/lib/automation_object/state/composite/hook_actions/new_screen.rb +0 -31
- data/lib/automation_object/state/composite/hook_actions/possible_screen_changes.rb +0 -22
- data/lib/automation_object/state/composite/hook_actions/show_modal.rb +0 -23
- data/lib/automation_object/state/composite/hook_actions/sleep.rb +0 -15
- data/lib/automation_object/state/composite/hook_actions/wait_for_elements.rb +0 -20
- data/lib/automation_object/state/composite/modal.rb +0 -45
- data/lib/automation_object/state/composite/screen.rb +0 -64
- data/lib/automation_object/state/composite/top.rb +0 -51
- data/lib/automation_object/state/session.rb +0 -54
@@ -3,11 +3,10 @@ require_relative 'action_loop'
|
|
3
3
|
|
4
4
|
module AutomationObject
|
5
5
|
module State
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
6
|
+
# Reset screen hook loop
|
7
|
+
class ResetScreen < ActionLoop
|
8
|
+
def single_run
|
9
|
+
composite.screen.reset
|
11
10
|
end
|
12
11
|
end
|
13
12
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'action_loop'
|
3
|
+
|
4
|
+
module AutomationObject
|
5
|
+
module State
|
6
|
+
# Show modal hook loop
|
7
|
+
class ShowModal < ActionLoop
|
8
|
+
def single_run
|
9
|
+
new_modal = composite.screen.modals[blue_prints]
|
10
|
+
|
11
|
+
return false if new_modal.load.live? == false
|
12
|
+
|
13
|
+
new_modal.activate
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'action_loop'
|
3
|
+
|
4
|
+
module AutomationObject
|
5
|
+
module State
|
6
|
+
# Wait for elements hook loop
|
7
|
+
class WaitForElements < ActionLoop
|
8
|
+
def single_run
|
9
|
+
blue_prints.each do |hook_element_requirement|
|
10
|
+
hook_element_requirement = ElementRequirement.new(driver, hook_element_requirement, 1)
|
11
|
+
return false unless hook_element_requirement.run
|
12
|
+
end
|
13
|
+
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '_base'
|
3
|
+
require_relative '_error'
|
4
|
+
|
5
|
+
require_relative 'element'
|
6
|
+
require_relative 'element_array'
|
7
|
+
require_relative 'element_hash'
|
8
|
+
|
9
|
+
module AutomationObject
|
10
|
+
module State
|
11
|
+
# Modal composite for managing state
|
12
|
+
class Modal < Base
|
13
|
+
has_one :load, interface: Hook
|
14
|
+
|
15
|
+
has_many :elements, interface: Element
|
16
|
+
has_many :element_arrays, interface: ElementArray
|
17
|
+
has_many :element_hashes, interface: ElementHash
|
18
|
+
|
19
|
+
def utilize
|
20
|
+
raise ModalNotActiveError, name unless active?
|
21
|
+
end
|
22
|
+
|
23
|
+
# Whether or not modal is active
|
24
|
+
attr_accessor :active
|
25
|
+
|
26
|
+
# @return [Boolean] screen is active or not
|
27
|
+
def active?
|
28
|
+
@active ||= false
|
29
|
+
end
|
30
|
+
|
31
|
+
def activate
|
32
|
+
@active = true
|
33
|
+
end
|
34
|
+
|
35
|
+
def deactivate
|
36
|
+
@active = false
|
37
|
+
reset
|
38
|
+
end
|
39
|
+
|
40
|
+
def reset
|
41
|
+
elements.values.map(&:reset)
|
42
|
+
element_arrays.values.map(&:reset)
|
43
|
+
element_hashes.values.map(&:reset)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '_base'
|
3
|
+
require_relative '_error'
|
4
|
+
|
5
|
+
require_relative 'modal'
|
6
|
+
require_relative 'hook'
|
7
|
+
require_relative 'element'
|
8
|
+
require_relative 'element_array'
|
9
|
+
require_relative 'element_hash'
|
10
|
+
|
11
|
+
module AutomationObject
|
12
|
+
module State
|
13
|
+
# Screen composite for managing state
|
14
|
+
class Screen < Base
|
15
|
+
attr_accessor :modal, :window_handle, :previous_screen_name
|
16
|
+
|
17
|
+
has_one :load, interface: Hook
|
18
|
+
|
19
|
+
# Children for this composite
|
20
|
+
has_many :modals, interface: Modal
|
21
|
+
|
22
|
+
has_many :elements, interface: Element
|
23
|
+
has_many :element_arrays, interface: ElementArray
|
24
|
+
has_many :element_hashes, interface: ElementHash
|
25
|
+
|
26
|
+
# Whether or not modal is active
|
27
|
+
attr_accessor :active
|
28
|
+
|
29
|
+
# @return [Boolean] screen is active or not
|
30
|
+
def active?
|
31
|
+
@active ||= false
|
32
|
+
end
|
33
|
+
|
34
|
+
def activate
|
35
|
+
@active = true
|
36
|
+
self.window_handle = driver.window_handle
|
37
|
+
end
|
38
|
+
|
39
|
+
def deactivate
|
40
|
+
@active = false
|
41
|
+
self.window_handle = nil
|
42
|
+
modals.values.map(&:deactivate)
|
43
|
+
reset
|
44
|
+
end
|
45
|
+
|
46
|
+
def utilize
|
47
|
+
raise ScreenNotActiveError, name unless active?
|
48
|
+
driver.window_handle = window_handle if window_handle != driver.window_handle
|
49
|
+
end
|
50
|
+
|
51
|
+
def close
|
52
|
+
raise ScreenNotActiveError, name unless active?
|
53
|
+
|
54
|
+
driver.window_handle = window_handle if window_handle != driver.window_handle
|
55
|
+
driver.close
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Boolean]
|
59
|
+
def closed?
|
60
|
+
!driver.window_handles.include?(window_handle)
|
61
|
+
end
|
62
|
+
|
63
|
+
def reset
|
64
|
+
elements.values.map(&:reset)
|
65
|
+
element_arrays.values.map(&:reset)
|
66
|
+
element_hashes.values.map(&:reset)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '_base'
|
3
|
+
require_relative '_error'
|
4
|
+
|
5
|
+
require_relative 'screen'
|
6
|
+
|
7
|
+
module AutomationObject
|
8
|
+
module State
|
9
|
+
# Top composite for managing state
|
10
|
+
class Top < Base
|
11
|
+
# Children for this composite
|
12
|
+
has_many :screens, interface: Screen
|
13
|
+
|
14
|
+
def initialize(*args)
|
15
|
+
super(*args)
|
16
|
+
|
17
|
+
driver.get(blue_prints.base_url) if blue_prints.base_url
|
18
|
+
set_initial_screen
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get the initial screen
|
22
|
+
# @raise [AutomationObject::State::NoInitialScreenError] if no initial screen
|
23
|
+
# @return [Symbol] screen name
|
24
|
+
def set_initial_screen
|
25
|
+
# If default screen then check if its live and set it
|
26
|
+
if blue_prints.default_screen
|
27
|
+
default_name = blue_prints.default_screen
|
28
|
+
|
29
|
+
raise AutomationObject::State::NoInitialScreenError if screens[default_name].load.live? != true
|
30
|
+
|
31
|
+
return screens[default_name].activate
|
32
|
+
end
|
33
|
+
|
34
|
+
screens.each_value do |screen|
|
35
|
+
next unless screen.load.live?
|
36
|
+
return screen.activate
|
37
|
+
end
|
38
|
+
|
39
|
+
raise AutomationObject::State::NoInitialScreenError
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require_relative 'state/
|
2
|
+
require_relative 'state/top'
|
3
3
|
|
4
4
|
module AutomationObject
|
5
5
|
# State Port, following port/adapter pattern
|
@@ -11,9 +11,9 @@ module AutomationObject
|
|
11
11
|
# Will use a composite to help control the state
|
12
12
|
# @param driver [AutomationObject::Driver::Driver] driver interface
|
13
13
|
# @param blue_prints [AutomationObject::BluePrint::Composite::Top] Top composite interface
|
14
|
-
# # @return [AutomationObject::State::
|
14
|
+
# # @return [AutomationObject::State::Top] Top instance
|
15
15
|
def create(driver, blue_prints)
|
16
|
-
|
16
|
+
Top.new(driver, blue_prints)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: automation_object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Blatter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1.12'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '1.12'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '11.3'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '11.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rubocop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 2.9
|
61
|
+
version: '2.9'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 2.9
|
68
|
+
version: '2.9'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: yard
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,16 +98,16 @@ dependencies:
|
|
98
98
|
name: pry
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
103
|
+
version: '0.10'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
110
|
+
version: '0.10'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: awesome_print
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -398,33 +398,30 @@ files:
|
|
398
398
|
- lib/automation_object/proxy/proxy.rb
|
399
399
|
- lib/automation_object/proxy/throttle_proxy.rb
|
400
400
|
- lib/automation_object/state.rb
|
401
|
-
- lib/automation_object/state/
|
402
|
-
- lib/automation_object/state/
|
403
|
-
- lib/automation_object/state/
|
404
|
-
- lib/automation_object/state/
|
405
|
-
- lib/automation_object/state/
|
406
|
-
- lib/automation_object/state/
|
407
|
-
- lib/automation_object/state/
|
408
|
-
- lib/automation_object/state/
|
409
|
-
- lib/automation_object/state/
|
410
|
-
- lib/automation_object/state/
|
411
|
-
- lib/automation_object/state/
|
412
|
-
- lib/automation_object/state/
|
413
|
-
- lib/automation_object/state/
|
414
|
-
- lib/automation_object/state/
|
415
|
-
- lib/automation_object/state/
|
416
|
-
- lib/automation_object/state/
|
417
|
-
- lib/automation_object/state/
|
418
|
-
- lib/automation_object/state/
|
419
|
-
- lib/automation_object/state/
|
420
|
-
- lib/automation_object/state/
|
421
|
-
- lib/automation_object/state/
|
422
|
-
- lib/automation_object/state/
|
423
|
-
- lib/automation_object/state/
|
424
|
-
- lib/automation_object/state/
|
425
|
-
- lib/automation_object/state/composite/top.rb
|
426
|
-
- lib/automation_object/state/error.rb
|
427
|
-
- lib/automation_object/state/session.rb
|
401
|
+
- lib/automation_object/state/_base.rb
|
402
|
+
- lib/automation_object/state/_common_element.rb
|
403
|
+
- lib/automation_object/state/_error.rb
|
404
|
+
- lib/automation_object/state/element.rb
|
405
|
+
- lib/automation_object/state/element_array.rb
|
406
|
+
- lib/automation_object/state/element_hash.rb
|
407
|
+
- lib/automation_object/state/element_proxy.rb
|
408
|
+
- lib/automation_object/state/hook.rb
|
409
|
+
- lib/automation_object/state/hook_action.rb
|
410
|
+
- lib/automation_object/state/hook_actions/action_loop.rb
|
411
|
+
- lib/automation_object/state/hook_actions/change_screen.rb
|
412
|
+
- lib/automation_object/state/hook_actions/change_to_previous_screen.rb
|
413
|
+
- lib/automation_object/state/hook_actions/close_modal.rb
|
414
|
+
- lib/automation_object/state/hook_actions/close_screen.rb
|
415
|
+
- lib/automation_object/state/hook_actions/element_requirement.rb
|
416
|
+
- lib/automation_object/state/hook_actions/new_screen.rb
|
417
|
+
- lib/automation_object/state/hook_actions/possible_screen_changes.rb
|
418
|
+
- lib/automation_object/state/hook_actions/reset_screen.rb
|
419
|
+
- lib/automation_object/state/hook_actions/show_modal.rb
|
420
|
+
- lib/automation_object/state/hook_actions/sleep.rb
|
421
|
+
- lib/automation_object/state/hook_actions/wait_for_elements.rb
|
422
|
+
- lib/automation_object/state/modal.rb
|
423
|
+
- lib/automation_object/state/screen.rb
|
424
|
+
- lib/automation_object/state/top.rb
|
428
425
|
- lib/automation_object/step_definitions.rb
|
429
426
|
- lib/automation_object/step_definitions/element.rb
|
430
427
|
- lib/automation_object/step_definitions/element_array.rb
|
@@ -1,81 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require_relative '../../helpers/composite'
|
3
|
-
|
4
|
-
module AutomationObject
|
5
|
-
module State
|
6
|
-
module Composite
|
7
|
-
# Parent composite class
|
8
|
-
class Base < ::AutomationObject::Composite
|
9
|
-
# @return [AutomationObject::State::Session]
|
10
|
-
attr_accessor :session
|
11
|
-
|
12
|
-
# @return [AutomationObject::BluePrint::Composite::]
|
13
|
-
attr_accessor :blue_prints
|
14
|
-
|
15
|
-
# @return [AutomationObject::Driver::Driver]
|
16
|
-
attr_accessor :driver
|
17
|
-
|
18
|
-
# @param session [AutomationObject::State::Session] session
|
19
|
-
# @param driver [AutomationObject::Driver] driver
|
20
|
-
# @param blue_prints [AutomationObject::BluePrint::Composite::Base] blue print composite
|
21
|
-
# @param name [Symbol] name of composite element
|
22
|
-
# @param parent [Object, nil] parent composite object
|
23
|
-
# @param location [String] string location for error/debugging purposes
|
24
|
-
def initialize(session, driver, blue_prints, name = :top, parent = nil, location = 'top')
|
25
|
-
self.session = session
|
26
|
-
self.driver = driver
|
27
|
-
self.blue_prints = blue_prints
|
28
|
-
|
29
|
-
super(name, parent, location)
|
30
|
-
end
|
31
|
-
|
32
|
-
# Overriding base get_child method
|
33
|
-
# @param name [Symbol] name of child
|
34
|
-
# @param args [Hash] args
|
35
|
-
def get_child(name, args)
|
36
|
-
child_location = location + "[#{name}]"
|
37
|
-
|
38
|
-
args.fetch(:interface).new(session,
|
39
|
-
driver,
|
40
|
-
blue_prints.send(name),
|
41
|
-
name, self, child_location)
|
42
|
-
end
|
43
|
-
|
44
|
-
# Overriding base get_children method
|
45
|
-
# @param name [Symbol] name of child
|
46
|
-
# @param args [Hash] args
|
47
|
-
# @return children [Array<Composite>] return children and names
|
48
|
-
def get_children(name, args)
|
49
|
-
children_hash = {}
|
50
|
-
|
51
|
-
blue_prints.send(name).each do |child_key, child_blue_prints|
|
52
|
-
child_location = location + "[#{child_key}]"
|
53
|
-
|
54
|
-
children_hash[child_key] = args.fetch(:interface).new(session,
|
55
|
-
driver,
|
56
|
-
child_blue_prints,
|
57
|
-
name, self, child_location)
|
58
|
-
end
|
59
|
-
|
60
|
-
children_hash
|
61
|
-
end
|
62
|
-
|
63
|
-
# Recursive function to reach parent screen
|
64
|
-
# Can return nil if above a screen!
|
65
|
-
# @return [AutomationObject::State::Composite::Screen,nil]
|
66
|
-
def screen
|
67
|
-
return nil if is_a?(Top)
|
68
|
-
|
69
|
-
# Should recursively call top until parent is nil
|
70
|
-
is_a?(Screen) ? self : parent.screen
|
71
|
-
end
|
72
|
-
|
73
|
-
# Recursive function to reach top
|
74
|
-
# @return [AutomationObject::State::Composite::Top]
|
75
|
-
def top
|
76
|
-
is_a?(Top) ? self : parent.top
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|