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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e3067a61bdc457c0ed1ce15521f79adc1fbddc02
4
- data.tar.gz: 17b710c74fc8587c8625497483661cf366cf2816
3
+ metadata.gz: 02300b6137cd03b63ebfef375d7d9de7402a8892
4
+ data.tar.gz: d353af7ed05239dca230b63825034ea30d74430e
5
5
  SHA512:
6
- metadata.gz: 45971725107ac1af7adde1dd5b21e209e8f17de1a09746d8f6ef129feb61fdccae846cb9b03da28a5b935171c8cc7737e5af12e58f7a214c27212e30e233f758
7
- data.tar.gz: e7d1d46c071f5ef0f668a0a984aa4533482829eee38303a234ddc4eb9b05adcc472b8065d753d0185b28eff9376da877b110b371ebf0f91af4883d393d37d2da
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
- * `#build!`: Creates ActiveRecord instances. Also supports FactoryGirl.
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 `#build!`:
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 field value.
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
- TODO: Pending API overhaul.
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.build! table, Users
144
+ Chop.create! table, Users
127
145
  Chop.diff! table, "table"
128
146
  Chop.fill_in! table
129
147
  ```
data/lib/chop.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require "chop/version"
2
- require "chop/builder"
2
+ require "chop/create"
3
3
  require "chop/table"
4
4
  require "chop/definition_list"
5
5
  require "chop/unordered_list"
@@ -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 Builder < Struct.new(:table, :klass, :block)
6
- def self.build! table, klass, &block
7
- new(table, klass, block).build!
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 build! cucumber_table = table
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)
@@ -1,7 +1,11 @@
1
- require "chop/base"
1
+ require "chop/diff"
2
2
 
3
3
  module Chop
4
- class DefinitionList < Base
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
@@ -1,7 +1,7 @@
1
1
  module Chop
2
2
  module DSL
3
3
  def create! table, klass, &block
4
- Builder.build! table, klass, &block
4
+ Create.create! table, klass, &block
5
5
  end
6
6
 
7
7
  def diff! selector, table, session: Capybara.current_session, &block
data/lib/chop/table.rb CHANGED
@@ -1,24 +1,10 @@
1
- require "chop/base"
1
+ require "chop/diff"
2
2
 
3
3
  module Chop
4
- class Table < Base
5
- private
6
-
7
- def default_selector
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
 
@@ -1,24 +1,10 @@
1
- require "chop/base"
1
+ require "chop/diff"
2
2
 
3
3
  module Chop
4
- class UnorderedList < Base
5
- private
6
-
7
- def default_selector
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
@@ -1,3 +1,3 @@
1
1
  module Chop
2
- VERSION = "0.13.2"
2
+ VERSION = "0.14.0"
3
3
  end
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.13.2
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-17 00:00:00.000000000 Z
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/base.rb
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