Skip to content

Commit

Permalink
Allow calling super over methods defined by accessors/regions
Browse files Browse the repository at this point in the history
  • Loading branch information
p0deje committed Feb 28, 2019
1 parent f39f6f9 commit 1c3283f
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 110 deletions.
90 changes: 49 additions & 41 deletions lib/watirsome/accessors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,15 @@ def proc_from_args(*args, &blk)
#
def define_element_accessor(name, method, *args, &block)
watir_args, custom_args = extract_custom_args(method, args)
define_method "#{name}_#{method}" do |*opts|
if block_given?
instance_exec(*opts, &block)
else
grab_elements(method, watir_args, custom_args)
include(Module.new do
define_method "#{name}_#{method}" do |*opts|
if block_given?
instance_exec(*opts, &block)
else
grab_elements(method, watir_args, custom_args)
end
end
end
end)
end

#
Expand All @@ -74,13 +76,15 @@ def define_element_accessor(name, method, *args, &block)
#
def define_click_accessor(name, method, *args, &block)
watir_args, custom_args = extract_custom_args(method, args)
define_method name do |*opts|
if block_given?
instance_exec(*opts, &block).click
else
grab_elements(method, watir_args, custom_args).click
include(Module.new do
define_method name do |*opts|
if block_given?
instance_exec(*opts, &block).click
else
grab_elements(method, watir_args, custom_args).click
end
end
end
end)
end

#
Expand All @@ -99,23 +103,25 @@ def define_click_accessor(name, method, *args, &block)
#
def define_read_accessor(name, method, *args, &block)
watir_args, custom_args = extract_custom_args(method, args)
define_method name do |*opts|
element = if block_given?
instance_exec(*opts, &block)
else
grab_elements(method, watir_args, custom_args)
end
case method
when :text_field, :textarea
element.value
when :select_list
element.options.detect(&:selected?).text
when :checkbox, :radio
element.set?
else
element.text
include(Module.new do
define_method name do |*opts|
element = if block_given?
instance_exec(*opts, &block)
else
grab_elements(method, watir_args, custom_args)
end
case method
when :text_field, :textarea
element.value
when :select_list
element.options.detect(&:selected?).text
when :checkbox, :radio
element.set?
else
element.text
end
end
end
end)
end

#
Expand All @@ -132,20 +138,22 @@ def define_read_accessor(name, method, *args, &block)
#
def define_set_accessor(name, method, *args, &block)
watir_args, custom_args = extract_custom_args(method, args)
define_method "#{name}=" do |*opts|
element = if block_given?
instance_exec(&block)
else
grab_elements(method, watir_args, custom_args)
end
if element.is_a?(Watir::Select)
element.select(*opts)
elsif element.respond_to?(:set)
element.set(*opts)
else
element.send_keys(*opts)
include(Module.new do
define_method "#{name}=" do |*opts|
element = if block_given?
instance_exec(&block)
else
grab_elements(method, watir_args, custom_args)
end
if element.is_a?(Watir::Select)
element.select(*opts)
elsif element.respond_to?(:set)
element.set(*opts)
else
element.send_keys(*opts)
end
end
end
end)
end

#
Expand Down
142 changes: 73 additions & 69 deletions lib/watirsome/regions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,94 +38,98 @@ def has_many(region_name, **opts, &block)
# FIXME: the generated method is far too complex, and deserves a proper refactoring
# rubocop:disable all
def define_region_accessor(region_name, within: nil, each: nil, collection_class: nil, region_class: nil, &block)
define_method(region_name) do
# FIXME: ['MakeItSizeOne'] is required when current class is anonymous (inline region)
class_path = self.class.name ? self.class.name.split('::') : ['MakeItSizeOne']
namespace = if class_path.size > 1
class_path.pop
Object.const_get(class_path.join('::'))
elsif class_path.size == 1
self.class
else
raise "Cannot understand namespace from #{class_path}"
end
include(Module.new do
define_method(region_name) do
# FIXME: ['MakeItSizeOne'] is required when current class is anonymous (inline region)
class_path = self.class.name ? self.class.name.split('::') : ['MakeItSizeOne']
namespace = if class_path.size > 1
class_path.pop
Object.const_get(class_path.join('::'))
elsif class_path.size == 1
self.class
else
raise "Cannot understand namespace from #{class_path}"
end

# This copy is required since `region_class` is declared outside of this defined function,
# and the function could change it
region_single_class = region_class
# This copy is required since `region_class` is declared outside of this defined function,
# and the function could change it
region_single_class = region_class

unless region_single_class
if block_given?
region_single_class = Class.new
region_single_class.class_eval { include(Watirsome) }
region_single_class.class_eval(&block)
else
singular_klass = region_name.to_s.split('_').map(&:capitalize).join
if each
collection_class_name = "#{singular_klass}Region"
singular_klass = singular_klass.sub(/s\z/, '')
unless region_single_class
if block_given?
region_single_class = Class.new
region_single_class.class_eval { include(Watirsome) }
region_single_class.class_eval(&block)
else
singular_klass = region_name.to_s.split('_').map(&:capitalize).join
if each
collection_class_name = "#{singular_klass}Region"
singular_klass = singular_klass.sub(/s\z/, '')
end
singular_klass << 'Region'
region_single_class = namespace.const_get(singular_klass)
end
singular_klass << 'Region'
region_single_class = namespace.const_get(singular_klass)
end
end

scope = case within
when Proc
instance_exec(&within)
when Hash
region_element.element(within)
else
region_element
end
scope = case within
when Proc
instance_exec(&within)
when Hash
region_element.element(within)
else
region_element
end

if each
elements = (scope.exists? ? scope.elements(each) : [])
if each
elements = (scope.exists? ? scope.elements(each) : [])

if collection_class_name && namespace.const_defined?(collection_class_name)
region_collection_class = namespace.const_get(collection_class_name)
elsif collection_class
region_collection_class = collection_class
else
return elements.map { |element| region_single_class.new(@browser, element, self) }
end
if collection_class_name && namespace.const_defined?(collection_class_name)
region_collection_class = namespace.const_get(collection_class_name)
elsif collection_class
region_collection_class = collection_class
else
return elements.map { |element| region_single_class.new(@browser, element, self) }
end

region_collection_class.class_eval do
include Enumerable
region_collection_class.class_eval do
include Enumerable

attr_reader :region_collection
attr_reader :region_collection

define_method(:initialize) do |browser, region_element, region_elements|
super(browser, region_element, self)
@region_collection = if region_elements.all? { |element| element.is_a?(Watir::Element) }
region_elements.map { |element| region_single_class.new(browser, element, self) }
else
region_elements
end
end
define_method(:initialize) do |browser, region_element, region_elements|
super(browser, region_element, self)
@region_collection = if region_elements.all? { |element| element.is_a?(Watir::Element) }
region_elements.map { |element| region_single_class.new(browser, element, self) }
else
region_elements
end
end

def each(&block)
region_collection.each(&block)
def each(&block)
region_collection.each(&block)
end
end
end

region_collection_class.new(@browser, scope, elements)
else
region_single_class.new(@browser, scope, self)
region_collection_class.new(@browser, scope, elements)
else
region_single_class.new(@browser, scope, self)
end
end
end
end)
end
# rubocop:enable all

def define_finder_method(region_name)
finder_method_name = region_name.to_s.sub(/s\z/, '')
define_method(finder_method_name) do |**opts|
__send__(region_name).find do |entity|
opts.all? do |key, value|
entity.__send__(key) == value
end
end || raise("No #{finder_method_name} matching: #{opts}.")
end
include(Module.new do
define_method(finder_method_name) do |**opts|
__send__(region_name).find do |entity|
opts.all? do |key, value|
entity.__send__(key) == value
end
end || raise("No #{finder_method_name} matching: #{opts}.")
end
end)
end
end
end
13 changes: 13 additions & 0 deletions spec/elements_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class GreetingPage
text_field :name2, -> { region_element.text_field(id: 'name') }
button :set2, -> { region_element.button(id: 'set_name') }
div :greeting2, -> { region_element.div(id: 'greeting') }

div :greeting3, id: 'greeting'

def greeting3
super.split(' ').first
end
end

RSpec.describe Watirsome do
Expand Down Expand Up @@ -75,5 +81,12 @@ class GreetingPage
expect(page.set2_button).to be_a Watir::Button
end
end

it 'supports calling super' do
GreetingPage.new(WatirHelper.browser).tap do |page|
page.browser.goto page.class::URL
expect(page.greeting3).to eq 'Hello'
end
end
end
end
13 changes: 13 additions & 0 deletions spec/regions/has_many_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ class ToDoListPage
end

has_many :wrapped_todo_lists, through: ToDoListCollection, class: ToDoList, each: { role: 'todo_list' }

has_many :home_todo_lists, region_class: ToDoList, each: { role: 'todo_list' }

def home_todo_lists
super.select { |todo_list| todo_list.title == 'Home' }
end
end

######################################################
Expand Down Expand Up @@ -99,5 +105,12 @@ class ToDoListPage
expect(page.todo_lists.last.items.count).to eq 3
end
end

it 'supports calling super' do
ToDoListPage.new(WatirHelper.browser).tap do |page|
page.browser.goto page.class::URL
expect(page.home_todo_lists.count).to eq 1
end
end
end
end
13 changes: 13 additions & 0 deletions spec/regions/has_one_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class ToDoListPage
span :name, role: 'name'
end
end

has_one :home_todo_list, region_class: ToDoList, within: { id: 'todos_home' }

def home_todo_list
super.title
end
end

#############################################
Expand Down Expand Up @@ -71,5 +77,12 @@ class ToDoListPage
expect(page.todo_list.item.name).to eq 'Review the PR-1234'
end
end

it 'supports calling super' do
ToDoListPage.new(WatirHelper.browser).tap do |page|
page.browser.goto page.class::URL
expect(page.home_todo_list).to eq 'Home'
end
end
end
end

0 comments on commit 1c3283f

Please sign in to comment.