chop 0.13.2 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -6
- data/lib/chop.rb +1 -1
- data/lib/chop/{builder.rb → create.rb} +4 -4
- data/lib/chop/definition_list.rb +6 -20
- data/lib/chop/diff.rb +168 -0
- data/lib/chop/dsl.rb +1 -1
- data/lib/chop/table.rb +5 -19
- data/lib/chop/unordered_list.rb +5 -19
- data/lib/chop/version.rb +1 -1
- metadata +4 -4
- data/lib/chop/base.rb +0 -95
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02300b6137cd03b63ebfef375d7d9de7402a8892
|
4
|
+
data.tar.gz: d353af7ed05239dca230b63825034ea30d74430e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb5dfb4be29ef2ca2e548b37f2176c8a3e7da2b83e3a985aa9d3f7a53d9c7b92a74d293ba567a995f5055b3824babecbb83f143a32a9d1ca52cb8169642d17a2
|
7
|
+
data.tar.gz: 07787e5e960bb7532855d46fbfbf363e855e2c0814b9fb56a1afcb87cb65440e239a679fc13acf31a0cb08ea6b3e12e290b5ab8eac959c3ddae860ca4cc6b968
|
data/README.md
CHANGED
@@ -16,13 +16,13 @@ end
|
|
16
16
|
|
17
17
|
Chop monkeypatches Cucumber tables with three new methods:
|
18
18
|
|
19
|
-
* `#
|
19
|
+
* `#create!`: Creates ActiveRecord instances. Also supports FactoryGirl.
|
20
20
|
* `#diff!`: Enhances existing method to also accept a CSS selector. Currently supports diffing `<table>`, `<dl>`, and `<ul>`.
|
21
21
|
* `#fill_in!`: Fills in a form on the current page.
|
22
22
|
|
23
23
|
All these methods accept blocks for customization.
|
24
24
|
|
25
|
-
### Block methods for `#
|
25
|
+
### Block methods for `#create!`:
|
26
26
|
|
27
27
|
Transform the attributes hash derived from the table before passing to `ActiveRecord.create!`.
|
28
28
|
|
@@ -36,12 +36,28 @@ High-level declarative transformations:
|
|
36
36
|
* `#rename`: Renames one or more fields.
|
37
37
|
|
38
38
|
All these methods are implemented in terms of the following low-level methods, useful for when you need more control over the transformation:
|
39
|
-
* `#field`: performs transformations on a specific
|
39
|
+
* `#field`: performs transformations on a specific oield value.
|
40
40
|
* `#transformation`: performs transformations on the attributes hash.
|
41
41
|
|
42
42
|
### Block methods for `#diff!`:
|
43
43
|
|
44
|
-
|
44
|
+
Transform the table of Capybara nodes before converting them to text and passing to `diff!`.
|
45
|
+
|
46
|
+
Overide Capybara finders:
|
47
|
+
* `#rows`: overrides existing default row finder.
|
48
|
+
* `#cells`: overrides existing default cell finder.
|
49
|
+
* `#text`: overrides existing default text finder.
|
50
|
+
* `#allow_not_found`: diffing against a missing element will diff against `[[]]` instead of raising an exception.
|
51
|
+
|
52
|
+
High-level declarative transformations:
|
53
|
+
* `#image`: Replaces the specified cell with the alt text of the first image within it.
|
54
|
+
|
55
|
+
All these methods are implemented in terms of the following low-level methods, useful for when you need more control over the transformation:
|
56
|
+
* `#header`: add or transform the table header, depending on block arity.
|
57
|
+
* `#header(key)`: transform the specified header column, specified either by numeric index, or by hash key.
|
58
|
+
* `#field`: performs transformations on a specific field value.
|
59
|
+
* `#hash_transformation`: performs arbitrary transformations on an array of hashes constructed by assuming a header row. Hash keys are downcased and underscored.
|
60
|
+
* `#transformation`: performs arbitrary transformations on the 2d array of Capybara nodes.
|
45
61
|
|
46
62
|
### Block methods for `#fill_in!`:
|
47
63
|
|
@@ -113,7 +129,9 @@ end
|
|
113
129
|
|
114
130
|
Then /^I should see the following "(.+?)" stories:$/ do |industry_name, table|
|
115
131
|
within "dfn", text: industry_name do
|
116
|
-
table.diff! "table"
|
132
|
+
table.diff! "table" do
|
133
|
+
image :image
|
134
|
+
end
|
117
135
|
end
|
118
136
|
end
|
119
137
|
```
|
@@ -123,7 +141,7 @@ end
|
|
123
141
|
Load `chop` before `cucumber` in your Gemfile, and call the two methods directly on the `Chop` module, passing the cucumber table in as the first argument.
|
124
142
|
|
125
143
|
```ruby
|
126
|
-
Chop.
|
144
|
+
Chop.create! table, Users
|
127
145
|
Chop.diff! table, "table"
|
128
146
|
Chop.fill_in! table
|
129
147
|
```
|
data/lib/chop.rb
CHANGED
@@ -2,9 +2,9 @@ require "active_support/core_ext/string/inflections"
|
|
2
2
|
require "active_support/core_ext/object/blank"
|
3
3
|
|
4
4
|
module Chop
|
5
|
-
class
|
6
|
-
def self.
|
7
|
-
new(table, klass, block).
|
5
|
+
class Create < Struct.new(:table, :klass, :block)
|
6
|
+
def self.create! table, klass, &block
|
7
|
+
new(table, klass, block).create!
|
8
8
|
end
|
9
9
|
|
10
10
|
attr_accessor :transformations
|
@@ -16,7 +16,7 @@ module Chop
|
|
16
16
|
instance_eval &other_block if block_given?
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
19
|
+
def create! cucumber_table = table
|
20
20
|
cucumber_table.hashes.map do |attributes|
|
21
21
|
transformations.each { |transformation| transformation.call(attributes) }
|
22
22
|
if klass.is_a?(Hash)
|
data/lib/chop/definition_list.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
require "chop/
|
1
|
+
require "chop/diff"
|
2
2
|
|
3
3
|
module Chop
|
4
|
-
class DefinitionList <
|
4
|
+
class DefinitionList < Diff
|
5
|
+
self.default_selector = "dl"
|
6
|
+
self.rows_finder = ->(root) { root.all("dfn") }
|
7
|
+
self.cells_finder = ->(row) { row.all("dt,dd") }
|
8
|
+
|
5
9
|
def column index, &block
|
6
10
|
transformation do |raw|
|
7
11
|
raw.map!.with_index do |row, row_index|
|
@@ -21,24 +25,6 @@ module Chop
|
|
21
25
|
raw
|
22
26
|
end
|
23
27
|
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def default_selector
|
28
|
-
"dl"
|
29
|
-
end
|
30
|
-
|
31
|
-
def default_rows_finder
|
32
|
-
Proc.new do |root|
|
33
|
-
root.all("dfn")
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def default_cells_finder
|
38
|
-
Proc.new do |row|
|
39
|
-
row.all("dt,dd")
|
40
|
-
end
|
41
|
-
end
|
42
28
|
end
|
43
29
|
|
44
30
|
Dl = DefinitionList
|
data/lib/chop/diff.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
require "active_support/core_ext/string/inflections"
|
2
|
+
require "active_support/core_ext/object/blank"
|
3
|
+
require "active_support/core_ext/class/attribute"
|
4
|
+
|
5
|
+
module Chop
|
6
|
+
class Diff < Struct.new(:selector, :table, :session, :block)
|
7
|
+
def self.diff! selector, table, session: Capybara.current_session, &block
|
8
|
+
new(selector, table, session, block).diff!
|
9
|
+
end
|
10
|
+
|
11
|
+
class_attribute :default_selector, :rows_finder, :cells_finder, :text_finder
|
12
|
+
|
13
|
+
self.rows_finder = -> { raise "Missing rows finder!" }
|
14
|
+
self.cells_finder = -> { raise "Missing cells finder!" }
|
15
|
+
self.text_finder = ->(cell) { cell.text }
|
16
|
+
|
17
|
+
def self.text_or_image_alt_finder
|
18
|
+
->(cell) do
|
19
|
+
text = cell.text
|
20
|
+
if text.blank? && image = cell.first("img")
|
21
|
+
image["alt"]
|
22
|
+
else
|
23
|
+
text
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_accessor :header_transformations, :transformations
|
29
|
+
|
30
|
+
def initialize selector = nil, table = nil, session = Capybara.current_session, block = nil, &other_block
|
31
|
+
super
|
32
|
+
self.selector ||= default_selector
|
33
|
+
self.header_transformations = []
|
34
|
+
self.transformations = []
|
35
|
+
instance_eval &block if block.respond_to?(:call)
|
36
|
+
instance_eval &other_block if block_given?
|
37
|
+
end
|
38
|
+
|
39
|
+
def header_transformation &block
|
40
|
+
header_transformations << block
|
41
|
+
end
|
42
|
+
|
43
|
+
def header index=nil, &block
|
44
|
+
if index
|
45
|
+
header_transformation do |row|
|
46
|
+
if index.is_a?(Symbol)
|
47
|
+
index = row.index do |cell|
|
48
|
+
text_finder.call(cell).parameterize.underscore.to_sym == index
|
49
|
+
end
|
50
|
+
end
|
51
|
+
row[index] = yield(row[index])
|
52
|
+
end
|
53
|
+
else
|
54
|
+
if block.arity.zero?
|
55
|
+
@new_header = yield
|
56
|
+
else
|
57
|
+
header_transformation do |row|
|
58
|
+
row.replace yield(row)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def transformation &block
|
65
|
+
transformations << block
|
66
|
+
end
|
67
|
+
|
68
|
+
def hash_transformation &block
|
69
|
+
transformation do |rows|
|
70
|
+
header = rows[0]
|
71
|
+
keys = header.to_a.map { |cell| cell.text.parameterize.underscore.to_sym }
|
72
|
+
body = rows[1..-1]
|
73
|
+
hashes = body.map { |row| Hash[keys.zip(row)] }
|
74
|
+
yield hashes
|
75
|
+
rows.replace [header] + hashes.map(&:values)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def field key
|
80
|
+
hash_transformation do |hashes|
|
81
|
+
hashes.map! do |row|
|
82
|
+
row.merge key => yield(row[key])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def image *keys
|
88
|
+
keys.each do |key|
|
89
|
+
field(key) do |cell|
|
90
|
+
if image = cell.first("img")
|
91
|
+
image["alt"]
|
92
|
+
else
|
93
|
+
cell
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def rows &block
|
100
|
+
self.rows_finder = block
|
101
|
+
end
|
102
|
+
|
103
|
+
def cells &block
|
104
|
+
self.cells_finder = block
|
105
|
+
end
|
106
|
+
|
107
|
+
def text &block
|
108
|
+
self.text_finder = block
|
109
|
+
end
|
110
|
+
|
111
|
+
def allow_not_found
|
112
|
+
@allow_not_found = true
|
113
|
+
end
|
114
|
+
|
115
|
+
def to_a
|
116
|
+
rows = rows_finder.call(root).map { |row| cells_finder.call(row).to_a }
|
117
|
+
rows = normalize(rows)
|
118
|
+
|
119
|
+
header = @new_header ? normalize([@new_header]).first : rows.shift
|
120
|
+
header_transformations.each do |transformation|
|
121
|
+
transformation.call(header)
|
122
|
+
header = normalize([header]).first
|
123
|
+
end
|
124
|
+
|
125
|
+
rows = [header] + rows
|
126
|
+
|
127
|
+
transformations.each do |transformation|
|
128
|
+
transformation.call(rows)
|
129
|
+
rows = normalize(rows)
|
130
|
+
end
|
131
|
+
|
132
|
+
rows.map do |row|
|
133
|
+
row.map { |cell| text_finder.call(cell) }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def diff! cucumber_table = table
|
138
|
+
cucumber_table.diff! to_a
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def normalize rows
|
144
|
+
max = rows.map(&:count).max
|
145
|
+
rows.map do |row|
|
146
|
+
row.to_a << "" while row.length < max
|
147
|
+
row.map { |cell| Node(cell) }
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def root
|
152
|
+
@root ||= begin
|
153
|
+
session.find(selector)
|
154
|
+
rescue Capybara::ElementNotFound
|
155
|
+
raise unless @allow_not_found
|
156
|
+
Node("")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def Node value
|
161
|
+
if value.respond_to?(:text)
|
162
|
+
value
|
163
|
+
else
|
164
|
+
Capybara::Node::Simple.new(value.to_s)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/lib/chop/dsl.rb
CHANGED
data/lib/chop/table.rb
CHANGED
@@ -1,24 +1,10 @@
|
|
1
|
-
require "chop/
|
1
|
+
require "chop/diff"
|
2
2
|
|
3
3
|
module Chop
|
4
|
-
class Table <
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
"table"
|
9
|
-
end
|
10
|
-
|
11
|
-
def default_rows_finder
|
12
|
-
Proc.new do |root|
|
13
|
-
root.all("tr")
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def default_cells_finder
|
18
|
-
Proc.new do |row|
|
19
|
-
row.all("td,th")
|
20
|
-
end
|
21
|
-
end
|
4
|
+
class Table < Diff
|
5
|
+
self.default_selector = "table"
|
6
|
+
self.rows_finder = ->(root) { root.all("tr") }
|
7
|
+
self.cells_finder = ->(row) { row.all("td,th") }
|
22
8
|
end
|
23
9
|
end
|
24
10
|
|
data/lib/chop/unordered_list.rb
CHANGED
@@ -1,24 +1,10 @@
|
|
1
|
-
require "chop/
|
1
|
+
require "chop/diff"
|
2
2
|
|
3
3
|
module Chop
|
4
|
-
class UnorderedList <
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
"ul"
|
9
|
-
end
|
10
|
-
|
11
|
-
def default_rows_finder
|
12
|
-
Proc.new do |root|
|
13
|
-
root.all("li")
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def default_cells_finder
|
18
|
-
Proc.new do |row|
|
19
|
-
[row]
|
20
|
-
end
|
21
|
-
end
|
4
|
+
class UnorderedList < Diff
|
5
|
+
self.default_selector = "ul"
|
6
|
+
self.rows_finder = ->(root) { root.all("li") }
|
7
|
+
self.cells_finder = ->(row) { [row] }
|
22
8
|
end
|
23
9
|
|
24
10
|
Ul = UnorderedList
|
data/lib/chop/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Micah Geisel
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -126,9 +126,9 @@ files:
|
|
126
126
|
- bin/setup
|
127
127
|
- chop.gemspec
|
128
128
|
- lib/chop.rb
|
129
|
-
- lib/chop/
|
130
|
-
- lib/chop/builder.rb
|
129
|
+
- lib/chop/create.rb
|
131
130
|
- lib/chop/definition_list.rb
|
131
|
+
- lib/chop/diff.rb
|
132
132
|
- lib/chop/dsl.rb
|
133
133
|
- lib/chop/form.rb
|
134
134
|
- lib/chop/table.rb
|
data/lib/chop/base.rb
DELETED
@@ -1,95 +0,0 @@
|
|
1
|
-
require "active_support/core_ext/object/blank"
|
2
|
-
|
3
|
-
module Chop
|
4
|
-
class Base < Struct.new(:selector, :table, :session, :block)
|
5
|
-
def self.diff! selector, table, session: Capybara.current_session, &block
|
6
|
-
new(selector, table, session, block).diff!
|
7
|
-
end
|
8
|
-
|
9
|
-
attr_accessor :rows_finder
|
10
|
-
attr_accessor :cells_finder
|
11
|
-
attr_accessor :transformations
|
12
|
-
|
13
|
-
def initialize selector = nil, table = nil, session = Capybara.current_session, block = nil, &other_block
|
14
|
-
super
|
15
|
-
self.selector ||= default_selector
|
16
|
-
self.rows_finder = default_rows_finder
|
17
|
-
self.cells_finder = default_cells_finder
|
18
|
-
self.transformations = []
|
19
|
-
instance_eval &block if block.respond_to?(:call)
|
20
|
-
instance_eval &other_block if block_given?
|
21
|
-
end
|
22
|
-
|
23
|
-
def transformation &block
|
24
|
-
transformations << block
|
25
|
-
end
|
26
|
-
|
27
|
-
def normalize
|
28
|
-
transformation do |raw|
|
29
|
-
max = raw.map(&:count).max
|
30
|
-
raw.map! do |row|
|
31
|
-
row << "" while row.length < max
|
32
|
-
row
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def rows &block
|
38
|
-
self.rows_finder = block
|
39
|
-
end
|
40
|
-
|
41
|
-
def cells &block
|
42
|
-
self.cells_finder = block
|
43
|
-
end
|
44
|
-
|
45
|
-
def allow_not_found
|
46
|
-
@allow_not_found = true
|
47
|
-
end
|
48
|
-
|
49
|
-
def to_a
|
50
|
-
results = rows_finder.call(root).map do |row|
|
51
|
-
row_to_text(row)
|
52
|
-
end
|
53
|
-
normalize
|
54
|
-
transformations.each { |transformation| transformation.call(results) }
|
55
|
-
results
|
56
|
-
end
|
57
|
-
|
58
|
-
def diff! cucumber_table = table
|
59
|
-
cucumber_table.diff! to_a
|
60
|
-
end
|
61
|
-
|
62
|
-
def hashes
|
63
|
-
rows = to_a.dup
|
64
|
-
header = rows.shift
|
65
|
-
rows.map do |row|
|
66
|
-
Hash[header.zip(row)]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def root
|
73
|
-
@root ||= begin
|
74
|
-
session.find(selector)
|
75
|
-
rescue Capybara::ElementNotFound
|
76
|
-
raise unless @allow_not_found
|
77
|
-
Capybara::Node::Simple.new("")
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def row_to_text row
|
82
|
-
cells_finder.call(row).map do |cell|
|
83
|
-
cell_to_text(cell)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def cell_to_text cell
|
88
|
-
text = cell.text
|
89
|
-
if text.blank? and image = cell.all("img").first
|
90
|
-
text = image["alt"]
|
91
|
-
end
|
92
|
-
text
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|