Class: Chop::Diff

Inherits:
Struct
  • Object
show all
Defined in:
lib/chop/diff.rb

Direct Known Subclasses

DefinitionList, Table

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(selector = nil, table = nil, session = Capybara.current_session, timeout = Capybara.default_max_wait_time, block = nil, &other_block) ⇒ Diff

Returns a new instance of Diff.



36
37
38
39
40
41
42
43
# File 'lib/chop/diff.rb', line 36

def initialize selector = nil, table = nil, session = Capybara.current_session, timeout = Capybara.default_max_wait_time, block = nil, &other_block
  super
  self.selector ||= default_selector
  self.header_transformations = []
  self.transformations = []
  instance_eval &block if block.respond_to?(:call)
  instance_eval &other_block if block_given?
end

Instance Attribute Details

#blockObject

Returns the value of attribute block

Returns:

  • (Object)

    the current value of block



9
10
11
# File 'lib/chop/diff.rb', line 9

def block
  @block
end

#header_transformationsObject

Returns the value of attribute header_transformations.



32
33
34
# File 'lib/chop/diff.rb', line 32

def header_transformations
  @header_transformations
end

#regex_fieldsObject

Returns the value of attribute regex_fields.



34
35
36
# File 'lib/chop/diff.rb', line 34

def regex_fields
  @regex_fields
end

#regex_templates_enabledObject

Returns the value of attribute regex_templates_enabled.



34
35
36
# File 'lib/chop/diff.rb', line 34

def regex_templates_enabled
  @regex_templates_enabled
end

#selectorObject

Returns the value of attribute selector

Returns:

  • (Object)

    the current value of selector



9
10
11
# File 'lib/chop/diff.rb', line 9

def selector
  @selector
end

#sessionObject

Returns the value of attribute session

Returns:

  • (Object)

    the current value of session



9
10
11
# File 'lib/chop/diff.rb', line 9

def session
  @session
end

#tableObject

Returns the value of attribute table

Returns:

  • (Object)

    the current value of table



9
10
11
# File 'lib/chop/diff.rb', line 9

def table
  @table
end

#timeoutObject

Returns the value of attribute timeout

Returns:

  • (Object)

    the current value of timeout



9
10
11
# File 'lib/chop/diff.rb', line 9

def timeout
  @timeout
end

#transformationsObject

Returns the value of attribute transformations.



32
33
34
# File 'lib/chop/diff.rb', line 32

def transformations
  @transformations
end

Class Method Details

.diff!(selector, table, session: Capybara.current_session, timeout: Capybara.default_max_wait_time, atomic: Chop.atomic_diff, errors: [], **kwargs, &block) ⇒ Object



10
11
12
13
14
15
16
17
18
# File 'lib/chop/diff.rb', line 10

def self.diff! selector, table, session: Capybara.current_session, timeout: Capybara.default_max_wait_time, atomic: Chop.atomic_diff, errors: [], **kwargs, &block
  errors += session.driver.invalid_element_errors
  errors += [Cucumber::MultilineArgument::DataTable::Different]
  session.document.synchronize timeout, errors: errors do
    instance = new(selector, table, session, timeout, block)
    instance.instance_variable_set(:@atomic, atomic)
    instance.diff! **kwargs
  end
end

Instance Method Details

#allow_not_foundObject



126
127
128
# File 'lib/chop/diff.rb', line 126

def allow_not_found
  @allow_not_found = true
end

#cell_to_image_filename(cell) ⇒ Object



20
21
22
23
24
# File 'lib/chop/diff.rb', line 20

def cell_to_image_filename cell
  cell.all("img", allow_reload: true).map do |img|
    File.basename(img[:src] || "").split("?")[0].sub(/-[0-9a-f]{64}/, '')
  end.first
end

#cells(&block) ⇒ Object



118
119
120
# File 'lib/chop/diff.rb', line 118

def cells &block
  self.cells_finder = block
end

#diff!(cucumber_table = table, **kwargs) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/chop/diff.rb', line 162

def diff! cucumber_table = table, **kwargs
  actual = to_a
  # FIXME should just delegate to Cucumber's #diff!. Cucumber needs to handle empty tables better.
  if !cucumber_table.raw.flatten.empty? && !actual.flatten.empty?
    if regex_templates_enabled
      cucumber_table = Chop::RegexTemplates.apply(cucumber_table, actual, regex_fields)
    end
    cucumber_table.diff! actual, **kwargs
  elsif cucumber_table.raw.flatten != actual.flatten
    raise Cucumber::MultilineArgument::DataTable::Different.new(cucumber_table)
  end
end

#field(key) ⇒ Object



98
99
100
101
102
103
104
# File 'lib/chop/diff.rb', line 98

def field key
  hash_transformation do |hashes|
    hashes.map! do |row|
      row.merge key => yield(row[key])
    end
  end
end

#hash_transformation(&block) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/chop/diff.rb', line 82

def hash_transformation &block
  transformation do |rows|
    header = rows[0]
    keys = header.to_a.map.with_index do |cell, index|
      key = cell.text.parameterize.underscore
      next key if key.present?
      next cell.text if cell.text.present?
      index + 1
    end
    body = rows[1..-1]
    hashes = body.map { |row| HashWithIndifferentAccess[keys.zip(row)] }
    yield hashes
    [header] + hashes.map(&:values)
  end
end

#header(index = nil, &block) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/chop/diff.rb', line 49

def header index=nil, &block
  if index
    header_transformation do |row|
      if index.is_a?(Symbol)
        index = row.index do |cell|
          text_finder.call(cell).parameterize.underscore.to_sym == index
        end
      end
      row[index] = yield(row[index])
      row
    end
  else
    if block.arity.zero?
      @new_header_block = block
    else
      header_transformation do |row|
        yield(row)
      end
    end
  end
end

#header_transformation(&block) ⇒ Object



45
46
47
# File 'lib/chop/diff.rb', line 45

def header_transformation &block
  header_transformations << block
end

#image(*keys) ⇒ Object



106
107
108
109
110
111
112
# File 'lib/chop/diff.rb', line 106

def image *keys
  keys.each do |key|
    field(key) do |cell|
      cell_to_image_filename(cell)
    end
  end
end

#regex(*fields) ⇒ Object

Enable embedded-regex templates within cells. Optionally restrict application to specific fields (by header name or 1-based index).



77
78
79
80
# File 'lib/chop/diff.rb', line 77

def regex *fields
  self.regex_templates_enabled = true
  self.regex_fields = fields unless fields.empty?
end

#rows(&block) ⇒ Object



114
115
116
# File 'lib/chop/diff.rb', line 114

def rows &block
  self.rows_finder = block
end

#text(&block) ⇒ Object



122
123
124
# File 'lib/chop/diff.rb', line 122

def text &block
  self.text_finder = block
end

#to_aObject



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/chop/diff.rb', line 130

def to_a
  wait_for_idle! if @atomic
  freeze_page_scripts! if @atomic
  @new_header = @new_header_block.call if @new_header_block
  rows = rows_finder.call(root).map { |row| cells_finder.call(row).to_a }
  rows = normalize(rows)

  header = @new_header ? normalize([@new_header]).first : rows.shift || []
  header = header_transformations.reduce(header) do |header, transformation|
    header = transformation.call(header)
    normalize([header]).first
  end

  if header
    rows = [header] + rows
    rows = normalize(rows)
  end

  rows = transformations.reduce(rows) do |rows, transformation|
    rows = transformation.call(rows)
    normalize(rows)
  end

  rows.map do |row|
    row.map do |cell|
      text_finder.call(cell)
    end
  end
ensure
  unfreeze_page_scripts! if @atomic
end

#transformation(&block) ⇒ Object



71
72
73
# File 'lib/chop/diff.rb', line 71

def transformation &block
  transformations << block
end