html_surgeon 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +24 -2
- data/html_surgeon.gemspec +1 -0
- data/lib/html_surgeon/auditor.rb +49 -0
- data/lib/html_surgeon/change.rb +16 -29
- data/lib/html_surgeon/change_set.rb +21 -14
- data/lib/html_surgeon/changes/add_css_class.rb +45 -12
- data/lib/html_surgeon/changes/replace_tag_name.rb +17 -5
- data/lib/html_surgeon/changes.rb +16 -0
- data/lib/html_surgeon/node_reverser.rb +79 -0
- data/lib/html_surgeon/service.rb +9 -1
- data/lib/html_surgeon/version.rb +1 -1
- data/lib/html_surgeon.rb +7 -0
- metadata +18 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94d817ba0e3871c050f1d56fd80034cfc389562c
|
4
|
+
data.tar.gz: aca28c4bcc429fd9e7ea1294c3f81896f641cda2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebe07e4c500cdaa9b95b852abb1e3b894eb3805c6ebfa9fac34fa0a56d34f3488700a025ac3f0cb1a5df1d6f194634b9724afea8c9769a09428148ea7219e8e1
|
7
|
+
data.tar.gz: c348f793ae6186dceb2f00db9269b45a0477d1e816b2084b672eb431b09d6d8e8a7d3147cff48ecb34bfc55ce35f12ec854ee6d28756eafb8f4bb068bcb3035e
|
data/README.md
CHANGED
@@ -110,7 +110,7 @@ If we have enabled audit, we'll get the changes applied to an element in an data
|
|
110
110
|
It will store, in JSON, an array with all the changes.
|
111
111
|
|
112
112
|
```ruby
|
113
|
-
surgeon = HtmlService.for(GIVEN_HTML)
|
113
|
+
surgeon = HtmlService.for(GIVEN_HTML, audit: true)
|
114
114
|
surgeon.css('.lol').replace_tag_name('span').add_css_class('hey').run
|
115
115
|
surgeon.html # =>
|
116
116
|
# <div>
|
@@ -123,7 +123,7 @@ surgeon.html # =>
|
|
123
123
|
# <li>2</li>
|
124
124
|
# </ul>
|
125
125
|
# </div>
|
126
|
-
# </div
|
126
|
+
# </div>
|
127
127
|
```
|
128
128
|
|
129
129
|
the attribute's value (formatted) is:
|
@@ -178,7 +178,24 @@ surgeon.css('div.to-be-changed').replace_name_tag('article')
|
|
178
178
|
surgeon.css('div.to-be-changed').add_css_class('applied-some-stuff')
|
179
179
|
```
|
180
180
|
|
181
|
+
## Rollback
|
182
|
+
|
183
|
+
the surgen can be used to revert any audited rollback. We can select what changes to rollback based on:
|
181
184
|
|
185
|
+
- `change_set`: The change_set UUID
|
186
|
+
- `changed_at`: The change timestamp
|
187
|
+
- `changed_from`: All changes which timestamp is more recent than the given time
|
188
|
+
|
189
|
+
We can also revert all audited changes.
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
surgeon = HtmlSurgeon.for(GIVEN_HTML)
|
193
|
+
|
194
|
+
surgeon.rollback.html # => returns the html with all events reverted
|
195
|
+
surgeon.rollback(change_set: uuid).html # => returns the html with only the given change set reverted
|
196
|
+
surgeon.rollback(changed_at: changed_at).html # => returns the html with only the change set with timestamp reverted
|
197
|
+
surgeon.rollback(changed_from: changed_from).html # => returns the html with any change sets with a timestamp more recent than `changed_from` reverted
|
198
|
+
```
|
182
199
|
|
183
200
|
## Installation
|
184
201
|
|
@@ -207,3 +224,8 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
207
224
|
|
208
225
|
Bug reports and pull requests are welcome on GitHub at https://github.com/eturino/html_surgeon.
|
209
226
|
|
227
|
+
|
228
|
+
## CHANGESET
|
229
|
+
|
230
|
+
### v 0.2.0
|
231
|
+
- added `rollback support
|
data/html_surgeon.gemspec
CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_dependency 'activesupport'
|
31
31
|
spec.add_dependency 'oj'
|
32
32
|
spec.add_dependency 'oj_mimic_json'
|
33
|
+
spec.add_dependency 'naught'
|
33
34
|
spec.add_development_dependency 'bundler', '~> 1.10'
|
34
35
|
spec.add_development_dependency 'rake', '~> 10.0'
|
35
36
|
spec.add_development_dependency 'rspec'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module HtmlSurgeon
|
2
|
+
class Auditor
|
3
|
+
attr_reader :node
|
4
|
+
|
5
|
+
def initialize(node)
|
6
|
+
@node = node
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_change(change_definition)
|
10
|
+
changes << change_definition
|
11
|
+
end
|
12
|
+
|
13
|
+
def apply(change_list = nil)
|
14
|
+
change_list ||= changes
|
15
|
+
if change_list.empty?
|
16
|
+
node.xpath(".//@#{DATA_CHANGE_AUDIT_ATTRIBUTE}").remove
|
17
|
+
else
|
18
|
+
node[DATA_CHANGE_AUDIT_ATTRIBUTE] = Oj.dump change_list
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def changes
|
23
|
+
@changes ||= load_changes_from_node
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def load_changes_from_node
|
29
|
+
current = node[DATA_CHANGE_AUDIT_ATTRIBUTE].presence
|
30
|
+
return [] unless current
|
31
|
+
|
32
|
+
Oj.load current, symbol_keys: true
|
33
|
+
end
|
34
|
+
|
35
|
+
NullAuditor = Naught.build do
|
36
|
+
def initialize(*)
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_change(change_definition)
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def apply
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/html_surgeon/change.rb
CHANGED
@@ -1,50 +1,37 @@
|
|
1
1
|
module HtmlSurgeon
|
2
2
|
|
3
3
|
class Change
|
4
|
-
|
4
|
+
def self.inherited(klass)
|
5
|
+
Changes.add_change_class(klass)
|
6
|
+
end
|
5
7
|
|
6
8
|
attr_reader :change_set
|
9
|
+
delegate :audit?, to: :change_set
|
10
|
+
delegate :uuid, :run_time, to: :change_set, prefix: true
|
7
11
|
|
8
12
|
def initialize(change_set:)
|
9
13
|
@change_set = change_set
|
10
14
|
end
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
def apply(node)
|
17
|
+
auditor = auditor_class.new(node)
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
apply_in element
|
19
|
-
|
20
|
-
apply_audit_change(element) if audit?
|
19
|
+
auditor.add_change(audit_data(node))
|
20
|
+
apply_in node
|
21
|
+
auditor.apply
|
21
22
|
|
22
23
|
self
|
23
24
|
end
|
24
25
|
|
26
|
+
def auditor_class
|
27
|
+
audit? ? Auditor : Auditor::NullAuditor
|
28
|
+
end
|
29
|
+
|
25
30
|
def log
|
26
31
|
raise AbstractMethodError, "a lazy developer has not implemented this method in #{self.class}"
|
27
32
|
end
|
28
33
|
|
29
34
|
private
|
30
|
-
|
31
|
-
def prepare_audit_change(element)
|
32
|
-
@audit_data = audit_data(element)
|
33
|
-
end
|
34
|
-
|
35
|
-
def apply_audit_change(element)
|
36
|
-
current = current_audit_data(element)
|
37
|
-
current << @audit_data
|
38
|
-
element[DATA_CHANGE_AUDIT_ATTRIBUTE] = Oj.dump current
|
39
|
-
end
|
40
|
-
|
41
|
-
def current_audit_data(element)
|
42
|
-
current = element[DATA_CHANGE_AUDIT_ATTRIBUTE].presence
|
43
|
-
return [] unless current
|
44
|
-
|
45
|
-
Oj.load current
|
46
|
-
end
|
47
|
-
|
48
35
|
def basic_audit_data
|
49
36
|
{
|
50
37
|
change_set: change_set_uuid,
|
@@ -52,11 +39,11 @@ module HtmlSurgeon
|
|
52
39
|
}
|
53
40
|
end
|
54
41
|
|
55
|
-
def audit_data(
|
42
|
+
def audit_data(node)
|
56
43
|
raise AbstractMethodError, "a lazy developer has not implemented this method in #{self.class}"
|
57
44
|
end
|
58
45
|
|
59
|
-
def apply_in(
|
46
|
+
def apply_in(_node)
|
60
47
|
raise AbstractMethodError, "a lazy developer has not implemented this method in #{self.class}"
|
61
48
|
end
|
62
49
|
|
@@ -3,12 +3,24 @@ module HtmlSurgeon
|
|
3
3
|
class ChangeSet
|
4
4
|
attr_reader :node_set, :base, :change_list, :uuid, :run_time
|
5
5
|
|
6
|
+
def self.create(node_set, base)
|
7
|
+
new_class.new node_set, base
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.new_class
|
11
|
+
Class.new(ChangeSet) do
|
12
|
+
Changes.change_classes.each do |klass|
|
13
|
+
include klass::ChangeSetMethods
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
def initialize(node_set, base)
|
7
19
|
@node_set = node_set
|
8
20
|
@base = base
|
9
21
|
@change_list = []
|
10
|
-
@uuid
|
11
|
-
@run_time
|
22
|
+
@uuid = SecureRandom.uuid
|
23
|
+
@run_time = nil
|
12
24
|
end
|
13
25
|
|
14
26
|
delegate :audit?, :html, to: :base
|
@@ -18,8 +30,8 @@ module HtmlSurgeon
|
|
18
30
|
def run
|
19
31
|
@run_time = Time.now.utc
|
20
32
|
|
21
|
-
node_set.each do |
|
22
|
-
|
33
|
+
node_set.each do |node|
|
34
|
+
apply_on_node(node)
|
23
35
|
end
|
24
36
|
|
25
37
|
self
|
@@ -31,21 +43,16 @@ module HtmlSurgeon
|
|
31
43
|
|
32
44
|
# CHANGES
|
33
45
|
|
34
|
-
|
35
|
-
change_list << Changes::ReplaceTagName.new(change_set: self, new_tag_name: new_tag_name)
|
36
|
-
self
|
37
|
-
end
|
46
|
+
private
|
38
47
|
|
39
|
-
def
|
40
|
-
change_list <<
|
48
|
+
def chain_add_change(change)
|
49
|
+
change_list << change
|
41
50
|
self
|
42
51
|
end
|
43
52
|
|
44
|
-
|
45
|
-
|
46
|
-
def apply_on_element(element)
|
53
|
+
def apply_on_node(node)
|
47
54
|
change_list.each do |change|
|
48
|
-
change.apply(
|
55
|
+
change.apply(node)
|
49
56
|
end
|
50
57
|
end
|
51
58
|
end
|
@@ -1,9 +1,13 @@
|
|
1
1
|
module HtmlSurgeon
|
2
2
|
module Changes
|
3
3
|
class AddCssClass < Change
|
4
|
-
|
4
|
+
AUDIT_TYPE = :add_css_class
|
5
|
+
|
5
6
|
CLASS_ATTRIBUTE = 'class'.freeze
|
6
7
|
CLASS_SEPARATOR = ' '.freeze
|
8
|
+
CLASS_XPATH = './/@class'
|
9
|
+
|
10
|
+
attr_reader :css_class
|
7
11
|
|
8
12
|
def initialize(css_class:, **other)
|
9
13
|
@css_class = css_class
|
@@ -16,24 +20,53 @@ module HtmlSurgeon
|
|
16
20
|
end
|
17
21
|
|
18
22
|
private
|
19
|
-
def apply_in(
|
20
|
-
|
21
|
-
classes << css_class
|
22
|
-
element.set_attribute(CLASS_ATTRIBUTE, classes.join(CLASS_SEPARATOR))
|
23
|
+
def apply_in(node)
|
24
|
+
self.class.add_class_to_node css_class, node
|
23
25
|
end
|
24
26
|
|
25
|
-
def audit_data(
|
26
|
-
basic_audit_data.merge type:
|
27
|
-
existed_before: had_class?(
|
27
|
+
def audit_data(node)
|
28
|
+
basic_audit_data.merge type: AUDIT_TYPE,
|
29
|
+
existed_before: self.class.had_class?(node, css_class),
|
28
30
|
class: css_class
|
29
31
|
end
|
30
32
|
|
31
|
-
def
|
32
|
-
|
33
|
+
def self.add_class_to_node(css_class, node)
|
34
|
+
classes = node_classes node
|
35
|
+
classes << css_class unless classes.include? css_class
|
36
|
+
set_classes_in_node(classes, node)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.remove_class_to_node(css_class, node)
|
40
|
+
classes = node_classes node
|
41
|
+
classes.delete css_class
|
42
|
+
if classes.empty?
|
43
|
+
node.xpath(CLASS_XPATH).remove
|
44
|
+
else
|
45
|
+
set_classes_in_node(classes, node)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.set_classes_in_node(classes, node)
|
50
|
+
node.set_attribute(CLASS_ATTRIBUTE, classes.join(CLASS_SEPARATOR))
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.node_classes(node)
|
54
|
+
node.get_attribute(CLASS_ATTRIBUTE).to_s.split(CLASS_SEPARATOR)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.had_class?(node, css_class)
|
58
|
+
node_classes(node).include? css_class
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.revert(node, change_definition)
|
62
|
+
return if change_definition[:existed_before]
|
63
|
+
remove_class_to_node(change_definition[:class], node)
|
33
64
|
end
|
34
65
|
|
35
|
-
|
36
|
-
|
66
|
+
module ChangeSetMethods
|
67
|
+
def add_css_class(css_class)
|
68
|
+
chain_add_change Changes::AddCssClass.new(change_set: self, css_class: css_class)
|
69
|
+
end
|
37
70
|
end
|
38
71
|
end
|
39
72
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module HtmlSurgeon
|
2
2
|
module Changes
|
3
3
|
class ReplaceTagName < Change
|
4
|
+
AUDIT_TYPE = :replace_tag_name
|
5
|
+
|
4
6
|
attr_reader :new_tag_name
|
5
7
|
|
6
8
|
def initialize(new_tag_name:, **other)
|
@@ -14,15 +16,25 @@ module HtmlSurgeon
|
|
14
16
|
end
|
15
17
|
|
16
18
|
private
|
17
|
-
def apply_in(
|
18
|
-
|
19
|
+
def apply_in(node)
|
20
|
+
node.name = new_tag_name
|
19
21
|
end
|
20
22
|
|
21
|
-
def audit_data(
|
22
|
-
basic_audit_data.merge type:
|
23
|
-
old:
|
23
|
+
def audit_data(node)
|
24
|
+
basic_audit_data.merge type: AUDIT_TYPE,
|
25
|
+
old: node.name,
|
24
26
|
new: new_tag_name
|
25
27
|
end
|
28
|
+
|
29
|
+
def self.revert(node, change_definition)
|
30
|
+
node.name = change_definition[:old]
|
31
|
+
end
|
32
|
+
|
33
|
+
module ChangeSetMethods
|
34
|
+
def replace_tag_name(new_tag_name)
|
35
|
+
chain_add_change Changes::ReplaceTagName.new(change_set: self, new_tag_name: new_tag_name)
|
36
|
+
end
|
37
|
+
end
|
26
38
|
end
|
27
39
|
end
|
28
40
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module HtmlSurgeon
|
2
|
+
module Changes
|
3
|
+
def self.change_classes
|
4
|
+
@change_classes ||= []
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.add_change_class(klass)
|
8
|
+
change_classes << klass
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.change_class_by_type(type)
|
12
|
+
type = type.to_s
|
13
|
+
change_classes.find { |klass| klass::AUDIT_TYPE.to_s == type }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module HtmlSurgeon
|
2
|
+
class NodeReverser
|
3
|
+
attr_reader :node, :change_set, :changed_at, :changed_from
|
4
|
+
|
5
|
+
def initialize(node:, change_set: nil, changed_at: nil, changed_from: nil)
|
6
|
+
@node = node
|
7
|
+
@change_set = change_set
|
8
|
+
@changed_at = changed_at
|
9
|
+
@changed_from = changed_from
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
changes_to_revert.each do |change_definition|
|
14
|
+
revert_change change_definition
|
15
|
+
end
|
16
|
+
|
17
|
+
write_remaining_changes
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def revert_change(change_definition)
|
23
|
+
klass = Changes.change_class_by_type change_definition[:type]
|
24
|
+
klass.revert(node, change_definition)
|
25
|
+
end
|
26
|
+
|
27
|
+
def write_remaining_changes
|
28
|
+
auditor.apply remaining_changes
|
29
|
+
end
|
30
|
+
|
31
|
+
def changes
|
32
|
+
auditor.changes
|
33
|
+
end
|
34
|
+
|
35
|
+
def remaining_changes
|
36
|
+
changes - changes_to_revert
|
37
|
+
end
|
38
|
+
|
39
|
+
def changes_to_revert
|
40
|
+
@changes_to_revert ||= load_changes_to_revert
|
41
|
+
end
|
42
|
+
|
43
|
+
def auditor
|
44
|
+
@auditor ||= Auditor.new node
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_changes_to_revert
|
48
|
+
changes.dup.tap do |rev_changes|
|
49
|
+
remove_by_change_set(rev_changes)
|
50
|
+
remove_by_changed_at(rev_changes)
|
51
|
+
remove_by_changed_from(rev_changes)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def remove_by_changed_from(rev_changes)
|
56
|
+
return unless changed_from.present?
|
57
|
+
|
58
|
+
changed_from_time = changed_from.to_time.utc
|
59
|
+
rev_changes.reject! do |change|
|
60
|
+
change[:changed_at].to_time.utc < changed_from_time
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def remove_by_changed_at(rev_changes)
|
65
|
+
return unless changed_at.present?
|
66
|
+
|
67
|
+
changed_at_time = changed_at.to_time.utc
|
68
|
+
rev_changes.reject! do |change|
|
69
|
+
change[:changed_at].to_time.utc != changed_at_time
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def remove_by_change_set(rev_changes)
|
74
|
+
return unless change_set.present?
|
75
|
+
|
76
|
+
rev_changes.reject! { |change| change[:change_set] != change_set }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/html_surgeon/service.rb
CHANGED
@@ -18,7 +18,15 @@ module HtmlSurgeon
|
|
18
18
|
|
19
19
|
def css(css_selector)
|
20
20
|
node_set = doc.css(css_selector)
|
21
|
-
ChangeSet.
|
21
|
+
ChangeSet.create(node_set, self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def rollback(change_set: nil, changed_at: nil, changed_from: nil)
|
25
|
+
doc.css("[#{DATA_CHANGE_AUDIT_ATTRIBUTE}]").each do |node|
|
26
|
+
NodeReverser.new(node: node, change_set: change_set, changed_at: changed_at, changed_from: changed_from).call
|
27
|
+
end
|
28
|
+
|
29
|
+
self
|
22
30
|
end
|
23
31
|
|
24
32
|
private
|
data/lib/html_surgeon/version.rb
CHANGED
data/lib/html_surgeon.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
|
+
require 'naught'
|
2
|
+
require 'oj'
|
1
3
|
require 'oj_mimic_json'
|
2
4
|
require 'nokogiri'
|
3
5
|
require 'active_support/all'
|
4
6
|
require 'html_surgeon/version'
|
5
7
|
require 'html_surgeon/abstract_method_error'
|
8
|
+
require 'html_surgeon/auditor'
|
9
|
+
require 'html_surgeon/node_reverser'
|
6
10
|
require 'html_surgeon/service'
|
7
11
|
require 'html_surgeon/change_set'
|
8
12
|
require 'html_surgeon/change'
|
13
|
+
require 'html_surgeon/changes'
|
9
14
|
require 'html_surgeon/changes/add_css_class'
|
10
15
|
require 'html_surgeon/changes/replace_tag_name'
|
11
16
|
|
12
17
|
module HtmlSurgeon
|
18
|
+
DATA_CHANGE_AUDIT_ATTRIBUTE = 'data-surgeon-audit'.freeze
|
19
|
+
|
13
20
|
def self.for(html_string, **options)
|
14
21
|
Service.new html_string, **options
|
15
22
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: html_surgeon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eduardo Turiño
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: naught
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,10 +140,13 @@ files:
|
|
126
140
|
- html_surgeon.gemspec
|
127
141
|
- lib/html_surgeon.rb
|
128
142
|
- lib/html_surgeon/abstract_method_error.rb
|
143
|
+
- lib/html_surgeon/auditor.rb
|
129
144
|
- lib/html_surgeon/change.rb
|
130
145
|
- lib/html_surgeon/change_set.rb
|
146
|
+
- lib/html_surgeon/changes.rb
|
131
147
|
- lib/html_surgeon/changes/add_css_class.rb
|
132
148
|
- lib/html_surgeon/changes/replace_tag_name.rb
|
149
|
+
- lib/html_surgeon/node_reverser.rb
|
133
150
|
- lib/html_surgeon/service.rb
|
134
151
|
- lib/html_surgeon/version.rb
|
135
152
|
homepage: https://github.com/eturino/html_surgeon
|