capybara-ui 0.10.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/capybara/ui.rb +33 -0
- data/lib/capybara/ui/assertions.rb +21 -0
- data/lib/{capybara-ui → capybara/ui}/capybara.rb +0 -0
- data/lib/capybara/ui/checkpoint.rb +113 -0
- data/lib/capybara/ui/conversions.rb +33 -0
- data/lib/capybara/ui/cucumber.rb +5 -0
- data/lib/capybara/ui/dsl.rb +109 -0
- data/lib/capybara/ui/instance_conversions.rb +21 -0
- data/lib/{capybara-ui → capybara/ui}/matchers.rb +4 -4
- data/lib/capybara/ui/optional_dependencies.rb +7 -0
- data/lib/capybara/ui/rails.rb +5 -0
- data/lib/capybara/ui/rails/role.rb +11 -0
- data/lib/capybara/ui/role.rb +21 -0
- data/lib/capybara/ui/text_table.rb +109 -0
- data/lib/capybara/ui/text_table/cell_text.rb +9 -0
- data/lib/capybara/ui/text_table/mapping.rb +42 -0
- data/lib/capybara/ui/text_table/transformations.rb +15 -0
- data/lib/capybara/ui/text_table/void_mapping.rb +10 -0
- data/lib/capybara/ui/version.rb +5 -0
- data/lib/capybara/ui/widgets.rb +63 -0
- data/lib/capybara/ui/widgets/check_box.rb +28 -0
- data/lib/capybara/ui/widgets/cucumber_methods.rb +75 -0
- data/lib/capybara/ui/widgets/document.rb +21 -0
- data/lib/capybara/ui/widgets/dsl.rb +49 -0
- data/lib/capybara/ui/widgets/field.rb +24 -0
- data/lib/capybara/ui/widgets/field_group.rb +331 -0
- data/lib/capybara/ui/widgets/form.rb +28 -0
- data/lib/capybara/ui/widgets/list.rb +202 -0
- data/lib/capybara/ui/widgets/list_item.rb +24 -0
- data/lib/capybara/ui/widgets/parts/container.rb +48 -0
- data/lib/capybara/ui/widgets/parts/struct.rb +119 -0
- data/lib/capybara/ui/widgets/radio_button.rb +64 -0
- data/lib/capybara/ui/widgets/select.rb +59 -0
- data/lib/capybara/ui/widgets/string_value.rb +45 -0
- data/lib/capybara/ui/widgets/table.rb +78 -0
- data/lib/capybara/ui/widgets/text_field.rb +29 -0
- data/lib/capybara/ui/widgets/widget.rb +394 -0
- data/lib/capybara/ui/widgets/widget/node_filter.rb +50 -0
- data/lib/capybara/ui/widgets/widget_class.rb +13 -0
- data/lib/capybara/ui/widgets/widget_name.rb +58 -0
- metadata +47 -43
- data/lib/capybara-ui.rb +0 -31
- data/lib/capybara-ui/assertions.rb +0 -19
- data/lib/capybara-ui/checkpoint.rb +0 -111
- data/lib/capybara-ui/conversions.rb +0 -31
- data/lib/capybara-ui/cucumber.rb +0 -5
- data/lib/capybara-ui/dsl.rb +0 -107
- data/lib/capybara-ui/instance_conversions.rb +0 -19
- data/lib/capybara-ui/optional_dependencies.rb +0 -5
- data/lib/capybara-ui/rails.rb +0 -5
- data/lib/capybara-ui/rails/role.rb +0 -9
- data/lib/capybara-ui/role.rb +0 -19
- data/lib/capybara-ui/text_table.rb +0 -107
- data/lib/capybara-ui/text_table/cell_text.rb +0 -7
- data/lib/capybara-ui/text_table/mapping.rb +0 -40
- data/lib/capybara-ui/text_table/transformations.rb +0 -13
- data/lib/capybara-ui/text_table/void_mapping.rb +0 -8
- data/lib/capybara-ui/version.rb +0 -3
- data/lib/capybara-ui/widgets.rb +0 -61
- data/lib/capybara-ui/widgets/check_box.rb +0 -26
- data/lib/capybara-ui/widgets/cucumber_methods.rb +0 -73
- data/lib/capybara-ui/widgets/document.rb +0 -19
- data/lib/capybara-ui/widgets/dsl.rb +0 -47
- data/lib/capybara-ui/widgets/field.rb +0 -22
- data/lib/capybara-ui/widgets/field_group.rb +0 -329
- data/lib/capybara-ui/widgets/form.rb +0 -26
- data/lib/capybara-ui/widgets/list.rb +0 -200
- data/lib/capybara-ui/widgets/list_item.rb +0 -22
- data/lib/capybara-ui/widgets/parts/container.rb +0 -46
- data/lib/capybara-ui/widgets/parts/struct.rb +0 -117
- data/lib/capybara-ui/widgets/radio_button.rb +0 -62
- data/lib/capybara-ui/widgets/select.rb +0 -57
- data/lib/capybara-ui/widgets/string_value.rb +0 -43
- data/lib/capybara-ui/widgets/table.rb +0 -76
- data/lib/capybara-ui/widgets/text_field.rb +0 -27
- data/lib/capybara-ui/widgets/widget.rb +0 -392
- data/lib/capybara-ui/widgets/widget/node_filter.rb +0 -48
- data/lib/capybara-ui/widgets/widget_class.rb +0 -11
- data/lib/capybara-ui/widgets/widget_name.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8569e04fe7e820a732b875283667700db0021f11
|
4
|
+
data.tar.gz: eab7f283b1ac93ceb0a1ff5db4d4319bf4f8b687
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 703a2e188f63c0e896b1a9df815dad5df846bcb30882d6618168b207b2f19a6736f84ddfe3c2751ed2cd92f536355c0320e0ea53de0964c562aa0704ac9db33d
|
7
|
+
data.tar.gz: cd41f9dd5368aba4585a365c321b399aa3c55c329990f68f66b4ebbd1181de4f98dc429c9d85f959176b559035db89e6003d8945ea4cfd0feeb8196d5d18a3cb
|
data/lib/capybara/ui.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'chronic'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'capybara'
|
4
|
+
|
5
|
+
require 'capybara/ui/optional_dependencies'
|
6
|
+
require 'capybara/ui/conversions'
|
7
|
+
require 'capybara/ui/instance_conversions'
|
8
|
+
require 'capybara/ui/checkpoint'
|
9
|
+
require 'capybara/ui/widgets'
|
10
|
+
require 'capybara/ui/text_table'
|
11
|
+
require 'capybara/ui/text_table/mapping'
|
12
|
+
require 'capybara/ui/text_table/void_mapping'
|
13
|
+
require 'capybara/ui/text_table/transformations'
|
14
|
+
require 'capybara/ui/text_table/cell_text'
|
15
|
+
require 'capybara/ui/capybara'
|
16
|
+
require 'capybara/ui/dsl'
|
17
|
+
|
18
|
+
module Capybara
|
19
|
+
module UI
|
20
|
+
# An exception that signals that something is missing.
|
21
|
+
class Missing < StandardError; end
|
22
|
+
class MissingWidget < StandardError; end
|
23
|
+
class AmbiguousWidget < StandardError; end
|
24
|
+
class InvalidOption < StandardError; end
|
25
|
+
class InvalidRadioButton < StandardError; end
|
26
|
+
|
27
|
+
def deprecate(method, alternate_method, once=false)
|
28
|
+
@deprecation_notified ||= {}
|
29
|
+
warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead" unless once and @deprecation_notified[method]
|
30
|
+
@deprecation_notified[method] = true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Capybara
|
2
|
+
module UI
|
3
|
+
module Assertions
|
4
|
+
def assert_visible(role, widget_name, *args)
|
5
|
+
eventually do
|
6
|
+
assert role.see?(widget_name, *args)
|
7
|
+
|
8
|
+
true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert_not_visible(role, widget_name, *args)
|
13
|
+
eventually do
|
14
|
+
refute role.see?(widget_name, *args)
|
15
|
+
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
File without changes
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Capybara
|
2
|
+
module UI
|
3
|
+
# A point in time where some condition, or some set of conditions, should be
|
4
|
+
# verified.
|
5
|
+
#
|
6
|
+
# @see http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Base#synchronize-instance_method,
|
7
|
+
# which inspired this class.
|
8
|
+
class Checkpoint
|
9
|
+
class ConditionNotMet < StandardError; end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :rescuable_errors
|
13
|
+
end
|
14
|
+
|
15
|
+
self.rescuable_errors = [StandardError]
|
16
|
+
|
17
|
+
if defined?(RSpec)
|
18
|
+
require 'rspec/expectations'
|
19
|
+
self.rescuable_errors << RSpec::Expectations::ExpectationNotMetError
|
20
|
+
end
|
21
|
+
|
22
|
+
class Timer
|
23
|
+
class Frozen < StandardError; end
|
24
|
+
|
25
|
+
def initialize(duration)
|
26
|
+
@duration = duration
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :duration
|
30
|
+
|
31
|
+
def expired?
|
32
|
+
duration < elapsed
|
33
|
+
end
|
34
|
+
|
35
|
+
def elapsed
|
36
|
+
now - start_time
|
37
|
+
end
|
38
|
+
|
39
|
+
def start
|
40
|
+
@start_time = now
|
41
|
+
end
|
42
|
+
|
43
|
+
def tick
|
44
|
+
sleep tick_duration
|
45
|
+
|
46
|
+
raise Frozen, 'time appears to be frozen' if frozen?
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def now
|
52
|
+
Time.now
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :start_time
|
56
|
+
|
57
|
+
def frozen?
|
58
|
+
now == start_time
|
59
|
+
end
|
60
|
+
|
61
|
+
def tick_duration
|
62
|
+
0.05
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Shortcut for instance level wait_for.
|
67
|
+
def self.wait_for(wait_time = Capybara.default_max_wait_time, &block)
|
68
|
+
new(wait_time).call(&block)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Initializes a new Checkpoint.
|
72
|
+
#
|
73
|
+
# @param wait_time how long this checkpoint will wait for its conditions to
|
74
|
+
# be met, in seconds.
|
75
|
+
def initialize(wait_time = Capybara.default_max_wait_time)
|
76
|
+
@timer = Timer.new(wait_time)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Executes +block+ repeatedly until it returns a "truthy" value or
|
80
|
+
# +wait_time+ expires.
|
81
|
+
#
|
82
|
+
# Swallows any StandardError or StandardError descendent until +wait_time+
|
83
|
+
# expires. If an exception is raised and the time has expired, that
|
84
|
+
# exception will be raised again.
|
85
|
+
#
|
86
|
+
# If the block does not return a "truthy" value until +wait_time+ expires,
|
87
|
+
# raises a Capybara::UI::Checkpoint::ConditionNotMet error.
|
88
|
+
#
|
89
|
+
# Returns whatever value is returned by the block.
|
90
|
+
def call(&condition)
|
91
|
+
timer.start
|
92
|
+
|
93
|
+
begin
|
94
|
+
yield or raise ConditionNotMet
|
95
|
+
rescue *rescuable_errors
|
96
|
+
raise if timer.expired?
|
97
|
+
|
98
|
+
timer.tick
|
99
|
+
|
100
|
+
retry
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
|
106
|
+
def rescuable_errors
|
107
|
+
self.class.rescuable_errors
|
108
|
+
end
|
109
|
+
|
110
|
+
attr_reader :timer
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Capybara
|
2
|
+
module UI
|
3
|
+
module Conversions
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def Boolean(val)
|
7
|
+
case val
|
8
|
+
when 'yes', 'true', true
|
9
|
+
true
|
10
|
+
when 'no', 'false', false, nil, ''
|
11
|
+
false
|
12
|
+
else
|
13
|
+
raise ArgumentError, "can't convert #{val.inspect} to boolean"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def List(valstr, &block)
|
18
|
+
vs = valstr.strip.split(/\s*,\s*/)
|
19
|
+
|
20
|
+
block ? vs.map(&block) : vs
|
21
|
+
end
|
22
|
+
|
23
|
+
def Timeish(val)
|
24
|
+
raise ArgumentError, "can't convert nil to Timeish" if val.nil?
|
25
|
+
|
26
|
+
return val if Date === val || Time === val || DateTime === val
|
27
|
+
|
28
|
+
Chronic.parse(val) or
|
29
|
+
raise ArgumentError, "can't parse #{val.inspect} to Timeish"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Capybara
|
2
|
+
module UI
|
3
|
+
module DSL
|
4
|
+
attr_writer :widget_lookup_scope
|
5
|
+
|
6
|
+
# Clicks the widget defined by +name+ and optional +args+.
|
7
|
+
#
|
8
|
+
# Makes no distinction between links or buttons.
|
9
|
+
#
|
10
|
+
# class MyWidget < Capybara::UI::Widget
|
11
|
+
# root { |text| ['.my-widget', text: text] }
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # <a href="#one" class="my-widget">One</li>
|
15
|
+
# # <a href="#two" class="my-widget">Two</li> <!-- clicks this node -->
|
16
|
+
# click :my_widget, 'Two'
|
17
|
+
def click(name, *args)
|
18
|
+
widget(name, *args).click
|
19
|
+
end
|
20
|
+
|
21
|
+
# Hovers the widget defined by +name+ and optional +args+.
|
22
|
+
def hover(name, *args)
|
23
|
+
widget(name, *args).hover
|
24
|
+
end
|
25
|
+
|
26
|
+
# Double clicks the widget defined by +name+ and optional +args+.
|
27
|
+
def double_click(name, *args)
|
28
|
+
widget(name, *args).double_click
|
29
|
+
end
|
30
|
+
|
31
|
+
# Right clicks the widget defined by +name+ and optional +args+.
|
32
|
+
def right_click(name, *args)
|
33
|
+
widget(name, *args).right_click
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Document] the current document with the class of the
|
37
|
+
# current object set as the widget lookup scope.
|
38
|
+
def document
|
39
|
+
Document.new(widget_lookup_scope)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Boolean] Whether one or more widgets exist in the current
|
43
|
+
# document.
|
44
|
+
def has_widget?(name, *args)
|
45
|
+
document.has_widget?(name, *args)
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_method :widget?, :has_widget?
|
49
|
+
|
50
|
+
def visible?(name, *args)
|
51
|
+
document.visible?(name, *args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def not_visible?(name, *args)
|
55
|
+
document.not_visible?(name, *args)
|
56
|
+
end
|
57
|
+
|
58
|
+
def set(name, fields)
|
59
|
+
widget(name).set fields
|
60
|
+
end
|
61
|
+
|
62
|
+
def submit(name, fields = {})
|
63
|
+
widget(name).submit_with fields
|
64
|
+
end
|
65
|
+
|
66
|
+
def value(name, *args)
|
67
|
+
widget(name, *args).value
|
68
|
+
end
|
69
|
+
|
70
|
+
def values(name, *args)
|
71
|
+
widgets(name, *args).map(&:value)
|
72
|
+
end
|
73
|
+
|
74
|
+
def visit(path)
|
75
|
+
Capybara.current_session.visit path
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns a widget instance for the given name.
|
79
|
+
#
|
80
|
+
# @param name [String, Symbol]
|
81
|
+
def widget(name, *args)
|
82
|
+
eventually { document.widget(name, *args) }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns a list of widget instances for the given name.
|
86
|
+
#
|
87
|
+
# @param name [String, Symbol]
|
88
|
+
def widgets(name, *args)
|
89
|
+
document.widgets(name, *args)
|
90
|
+
end
|
91
|
+
|
92
|
+
def widget_lookup_scope
|
93
|
+
@widget_lookup_scope ||= default_widget_lookup_scope
|
94
|
+
end
|
95
|
+
|
96
|
+
# re-run one or more assertions until either they all pass,
|
97
|
+
# or Capybara::UI times out, which will result in a test failure.
|
98
|
+
def eventually(wait_time = Capybara.default_max_wait_time, &block)
|
99
|
+
Checkpoint.wait_for wait_time, &block
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def default_widget_lookup_scope
|
105
|
+
Module === self ? self : self.class
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Capybara
|
2
|
+
module UI
|
3
|
+
module InstanceConversions
|
4
|
+
def self.included(base)
|
5
|
+
base.send :include, Capybara::UI::Conversions
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_boolean
|
9
|
+
Boolean(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_a
|
13
|
+
List(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_time
|
17
|
+
Timeish(self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -2,9 +2,9 @@ begin
|
|
2
2
|
require 'rspec/matchers'
|
3
3
|
require 'rspec/version'
|
4
4
|
|
5
|
-
unless Gem::Version.new(RSpec::Version::STRING) >= Gem::Version.new(
|
5
|
+
unless Gem::Version.new(RSpec::Version::STRING) >= Gem::Version.new(Capybara::UI::OptionalDependencies::RSPEC_VERSION)
|
6
6
|
raise LoadError,
|
7
|
-
"requires RSpec version #{
|
7
|
+
"requires RSpec version #{Capybara::UI::OptionalDependencies::RSPEC_VERSION} or later. " \
|
8
8
|
"You have #{RSpec::Version::STRING}."
|
9
9
|
end
|
10
10
|
|
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
match do |role|
|
13
13
|
begin
|
14
14
|
eventually { role.see?(widget_name, *args) }
|
15
|
-
rescue
|
15
|
+
rescue Capybara::UI::Checkpoint::ConditionNotMet
|
16
16
|
false
|
17
17
|
end
|
18
18
|
end
|
@@ -20,7 +20,7 @@ begin
|
|
20
20
|
match_when_negated do |role|
|
21
21
|
begin
|
22
22
|
eventually { !role.see?(widget_name, *args) }
|
23
|
-
rescue
|
23
|
+
rescue Capybara::UI::Checkpoint::ConditionNotMet
|
24
24
|
false
|
25
25
|
end
|
26
26
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Capybara
|
2
|
+
module UI
|
3
|
+
class Role < Capybara::UI::Rails::Role
|
4
|
+
extend Widgets::DSL
|
5
|
+
|
6
|
+
include Capybara::UI::DSL
|
7
|
+
|
8
|
+
def see?(name, *args)
|
9
|
+
if respond_to?("see_#{name}?")
|
10
|
+
send("see_#{name}?", *args)
|
11
|
+
else
|
12
|
+
visible?(name, *args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
self.class.name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Capybara
|
2
|
+
module UI
|
3
|
+
class TextTable
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
include Conversions
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def Array(table)
|
11
|
+
new(table).to_a
|
12
|
+
end
|
13
|
+
|
14
|
+
def Hash(table)
|
15
|
+
new(table).to_h
|
16
|
+
end
|
17
|
+
|
18
|
+
def map(name, options = {}, &block)
|
19
|
+
case name
|
20
|
+
when :*
|
21
|
+
set_default_mapping options, &block
|
22
|
+
else
|
23
|
+
set_mapping name, options, &block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def mappings
|
28
|
+
@mappings ||= Hash.
|
29
|
+
new { |h, k| h[k] = Mapping.new }.
|
30
|
+
merge(with_parent_mappings)
|
31
|
+
end
|
32
|
+
|
33
|
+
def skip(name)
|
34
|
+
case name
|
35
|
+
when :*
|
36
|
+
set_default_mapping VoidMapping
|
37
|
+
else
|
38
|
+
raise ArgumentError, "can't convert #{name.inspect} to name"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def set_default_mapping(options, &block)
|
45
|
+
case options
|
46
|
+
when Hash
|
47
|
+
@mappings = Hash.
|
48
|
+
new { |h, k|
|
49
|
+
h[k] = Mapping.new(key_transformer: options[:to],
|
50
|
+
value_transformer: block) }.
|
51
|
+
merge(mappings)
|
52
|
+
when Class
|
53
|
+
@mappings = Hash.new { |h, k| h[k] = options.new }.merge(mappings)
|
54
|
+
else
|
55
|
+
raise ArgumentError, "can't convert #{options.inspect} to mapping"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_mapping(name, options, &block)
|
60
|
+
mappings[name] = Mapping.
|
61
|
+
new(key: options[:to], value_transformer: block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def with_parent_mappings
|
65
|
+
if superclass.respond_to?(:mappings)
|
66
|
+
superclass.send(:mappings).dup
|
67
|
+
else
|
68
|
+
{}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def_delegators 'self.class', :mappings
|
74
|
+
|
75
|
+
def initialize(table)
|
76
|
+
self.table = table
|
77
|
+
end
|
78
|
+
|
79
|
+
def each(&block)
|
80
|
+
rows.each(&block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def rows
|
84
|
+
@rows ||= table.hashes.map { |h| new_row(h) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def single_row
|
88
|
+
@single_row ||= new_row(table.rows_hash)
|
89
|
+
end
|
90
|
+
|
91
|
+
alias_method :to_a, :rows
|
92
|
+
alias_method :to_h, :single_row
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
attr_accessor :table
|
97
|
+
|
98
|
+
def new_row(hash)
|
99
|
+
hash.each_with_object({}) { |(k, v), h|
|
100
|
+
mapping_for(k).set(self, h, k, CellText.new(v))
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def mapping_for(header)
|
105
|
+
mappings[header]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|