deltoid 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'http://rubygems.org'
2
+ gem 'nokogiri', '~> 1.4'
3
+
4
+ group :development do
5
+ gem 'bundler', '~> 1.0'
6
+ gem 'jeweler', '~> 1.5'
7
+ gem 'rspec', '~> 2.1'
8
+ gem 'unindentable'
9
+ end
10
+
11
+ # gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ git (1.2.5)
6
+ jeweler (1.5.1)
7
+ bundler (~> 1.0.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ nokogiri (1.4.3.1)
11
+ rake (0.8.7)
12
+ rspec (2.1.0)
13
+ rspec-core (~> 2.1.0)
14
+ rspec-expectations (~> 2.1.0)
15
+ rspec-mocks (~> 2.1.0)
16
+ rspec-core (2.1.0)
17
+ rspec-expectations (2.1.0)
18
+ diff-lcs (~> 1.1.2)
19
+ rspec-mocks (2.1.0)
20
+ unindentable (0.0.3)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ bundler (~> 1.0)
27
+ jeweler (~> 1.5)
28
+ nokogiri (~> 1.4)
29
+ rspec (~> 2.1)
30
+ unindentable
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 David James
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Deltoid
2
+
3
+ Deltoid finds differences between HTML files.
4
+
5
+ ## Contributing to deltoid
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature or bug fix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ ## Copyright
16
+
17
+ Copyright (c) 2010 David James. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification
15
+ # (See http://docs.rubygems.org/read/chapter/20 for more options)
16
+ gem.name = "deltoid"
17
+ gem.homepage = "http://github.com/djsun/deltoid"
18
+ gem.license = "MIT"
19
+ gem.summary = %Q{Deltoid finds differences between two or more HTML documents.}
20
+ gem.description = %Q{Deltoid diffs HTML documents using a relatively simple N-way algorithm. It reports deltas as an array of hashes, where each hash contains :content, :xpath, and :index keys.}
21
+ gem.email = "davidcjames@gmail.com"
22
+ gem.authors = ["David James"]
23
+
24
+ gem.add_runtime_dependency 'nokogiri', '~> 1.4'
25
+
26
+ gem.add_development_dependency 'bundler', '~> 1.0'
27
+ gem.add_development_dependency 'jeweler', '~> 1.5'
28
+ gem.add_development_dependency 'rspec', '~> 2.1'
29
+ gem.add_development_dependency 'unindentable'
30
+ end
31
+ Jeweler::RubygemsDotOrgTasks.new
32
+
33
+ require 'rspec/core/rake_task'
34
+ RSpec::Core::RakeTask.new(:spec) do |task|
35
+ task.rspec_opts = "-c -fd" # color, documentation format
36
+ end
37
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/deltoid.rb ADDED
@@ -0,0 +1,154 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'set'
4
+ require 'nokogiri'
5
+
6
+ class Deltoid
7
+ def initialize(strings)
8
+ @strings = strings
9
+ @parsed = @strings.map { |s| self.class.parse(s) }
10
+ end
11
+
12
+ # Find the differences between the documents.
13
+ def delta
14
+ deltas = self.class.delta_documents(@parsed)
15
+ self.class.friendly_deltas(deltas, @parsed)
16
+ end
17
+
18
+ def self.friendly_deltas(deltas, root_nodes)
19
+ deltas.map do |delta|
20
+ root = delta.ancestors.last
21
+ {
22
+ :index => root_nodes.find_index(root),
23
+ :content => delta.content,
24
+ :xpath => delta.path,
25
+ }
26
+ end
27
+ end
28
+
29
+ # Returns an array of nodes that are different between +documents+.
30
+ def self.delta_documents(documents)
31
+ roots = documents.map { |document| document.root }
32
+ delta_nodes(roots)
33
+ end
34
+
35
+ # Returns an array of nodes that are different between +nodes+.
36
+ #
37
+ # Idea: could this be rewritten as a special case of delta_nodes_group?
38
+ def self.delta_nodes(nodes)
39
+ deltas = []
40
+ deltas.concat(nodes) unless match?(nodes)
41
+ deltas.concat(delta_children_nodes(nodes))
42
+ end
43
+
44
+ # Returns an array of nodes that are different between +nodes+.
45
+ def self.delta_children_nodes(nodes)
46
+ children = nodes.map { |node| node.children.select { |k| k.element? } }
47
+ delta_nodes_group(children)
48
+ end
49
+
50
+ def self.delta_nodes_group(nodes_group)
51
+ matches_group = find_matches_group(nodes_group)
52
+ deltas = find_deltas(nodes_group, matches_group)
53
+ matches_group.each do |matches|
54
+ deltas.concat(delta_children_nodes(matches))
55
+ end
56
+ deltas
57
+ end
58
+
59
+ # Parameters:
60
+ # +all_nodes_group+ is an array of an array of nodes, with the same
61
+ # length as the number of documents being diffed.
62
+ # Returns:
63
+ # an array of array of nodes that match each other
64
+ def self.find_matches_group(all_nodes_group)
65
+ first_nodes = all_nodes_group.first
66
+ remaining_nodes_group = all_nodes_group.drop(1)
67
+ matches_group = []
68
+ first_nodes.each do |node|
69
+ matches = find_matches_in(node, remaining_nodes_group)
70
+ matches_group << matches unless matches.empty?
71
+ end
72
+ matches_group
73
+ end
74
+
75
+ # If +node+ can be found in each of +remaining_nodes_group+, return an
76
+ # array of each matching node. Otherwise, return [].
77
+ #
78
+ # Parameters:
79
+ # +nodes_group+ is an array of an array of nodes, with the same length
80
+ # as the number of documents being diffed.
81
+ # Returns:
82
+ # An array containing each matched node; otherwise [].
83
+ def self.find_matches_in(node, remaining_nodes_group)
84
+ matches = [node]
85
+ remaining_nodes_group.each do |nodes_group|
86
+ match = find_match(node, nodes_group)
87
+ if match
88
+ matches << match
89
+ else
90
+ matches = []
91
+ break
92
+ end
93
+ end
94
+ matches
95
+ end
96
+
97
+ # If +the_node+ matches a node in +node_group+, return the latter node.
98
+ # Otherwise, return nil.
99
+ #
100
+ # Note: stops after finding the first match.
101
+ def self.find_match(the_node, nodes)
102
+ nodes.each do |node|
103
+ return node if match?([the_node, node])
104
+ end
105
+ nil
106
+ end
107
+
108
+ # Figure out the deltas (differences) based on:
109
+ # +nodes_group+ (an array of array of nodes)
110
+ # +matches_group+ (an array of array of nodes)
111
+ def self.find_deltas(nodes_group, matches_group)
112
+ nodes_group.flatten - matches_group.flatten
113
+ end
114
+
115
+ # Do the +nodes+ match?
116
+ def self.match?(nodes)
117
+ names = nodes.map { |node| node.name }.uniq
118
+ names.length == 1 && attributes_match?(nodes) && content_match?(nodes)
119
+ end
120
+
121
+ # Do the attributes of the +nodes+ match?
122
+ def self.attributes_match?(nodes)
123
+ attributes = nodes.map { |node| attributes(node) }.uniq
124
+ attributes.length == 1
125
+ end
126
+
127
+ # Does the content of the +nodes+ match? (Note: only applies to nodes whose
128
+ # children are all text nodes.)
129
+ def self.content_match?(nodes)
130
+ return true if nodes.any? { |node| !all_children_are_text?(node) }
131
+ content = nodes.map { |node| node.content }.uniq
132
+ content.length == 1
133
+ end
134
+
135
+ def self.attributes(node)
136
+ map = {}
137
+ node.attributes.values.each do |attribute|
138
+ name, value = attribute.name, attribute.value
139
+ map[name] = value
140
+ end
141
+ map
142
+ end
143
+
144
+ # (Internal API)
145
+ def self.all_children_are_text?(node)
146
+ node.children.all? { |x| x.text? }
147
+ end
148
+
149
+ # (Internal API)
150
+ def self.parse(item)
151
+ Nokogiri::HTML::Document.parse(item)
152
+ end
153
+
154
+ end
data/spec/1_spec.rb ADDED
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe '3 identical documents' do
4
+ include Unindentable
5
+
6
+ def template
7
+ unindent <<-END
8
+ <p class="intro">Introduction...</p>
9
+ <ul class="list">
10
+ <li>A</li>
11
+ <li>B</li>
12
+ <li>C</li>
13
+ </ul>
14
+ <p class="summary">Summary...</p>
15
+ END
16
+ end
17
+
18
+ before do
19
+ docs = [template, template, template]
20
+ @deltoid = Deltoid.new(docs)
21
+ end
22
+
23
+ it 'delta should be correct' do
24
+ @deltoid.delta.should == []
25
+ end
26
+
27
+ end
data/spec/2_spec.rb ADDED
@@ -0,0 +1,47 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe '3 documents, 3 <li>, 1 different <li>' do
4
+ include Unindentable
5
+
6
+ def template(x)
7
+ unindent <<-END
8
+ <html>
9
+ <body>
10
+ <p class="begin">Begin</p>
11
+ <ul class="list">
12
+ <li>A</li>
13
+ <li>B</li>
14
+ <li>#{x}</li>
15
+ </ul>
16
+ <p class="end">End</p>
17
+ </body>
18
+ </html>
19
+ END
20
+ end
21
+
22
+ before do
23
+ docs = [template('X'), template('Y'), template('Z')]
24
+ @deltoid = Deltoid.new(docs)
25
+ end
26
+
27
+ it 'delta should be correct' do
28
+ actual = @deltoid.delta
29
+ actual.length.should == 3
30
+ actual.should include({
31
+ :index => 0,
32
+ :content => 'X',
33
+ :xpath => '/html/body/ul/li[3]',
34
+ })
35
+ actual.should include({
36
+ :index => 1,
37
+ :content => 'Y',
38
+ :xpath => '/html/body/ul/li[3]',
39
+ })
40
+ actual.should include({
41
+ :index => 2,
42
+ :content => 'Z',
43
+ :xpath => '/html/body/ul/li[3]',
44
+ })
45
+ end
46
+
47
+ end
data/spec/3_spec.rb ADDED
@@ -0,0 +1,47 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe '3 documents, id attribute, 3 <li>' do
4
+ include Unindentable
5
+
6
+ def template(x)
7
+ unindent <<-END
8
+ <html>
9
+ <body>
10
+ <p class="begin" id="begin_0">Begin</p>
11
+ <ul class="list">
12
+ <li>A</li>
13
+ <li>B</li>
14
+ <li>#{x}</li>
15
+ </ul>
16
+ <p class="end">End</p>
17
+ </body>
18
+ </html>
19
+ END
20
+ end
21
+
22
+ before do
23
+ docs = [template('X'), template('Y'), template('Z')]
24
+ @deltoid = Deltoid.new(docs)
25
+ end
26
+
27
+ it 'delta should be correct' do
28
+ actual = @deltoid.delta
29
+ actual.length.should == 3
30
+ actual.should include({
31
+ :index => 0,
32
+ :content => 'X',
33
+ :xpath => '/html/body/ul/li[3]',
34
+ })
35
+ actual.should include({
36
+ :index => 1,
37
+ :content => 'Y',
38
+ :xpath => '/html/body/ul/li[3]',
39
+ })
40
+ actual.should include({
41
+ :index => 2,
42
+ :content => 'Z',
43
+ :xpath => '/html/body/ul/li[3]',
44
+ })
45
+ end
46
+
47
+ end
data/spec/4_spec.rb ADDED
@@ -0,0 +1,48 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe '3 documents, 4 <li>' do
4
+ include Unindentable
5
+
6
+ def template(x)
7
+ unindent <<-END
8
+ <html>
9
+ <body>
10
+ <p class="begin">Begin</p>
11
+ <ul class="list">
12
+ <li>A</li>
13
+ <li>B</li>
14
+ <li>#{x}</li>
15
+ <li>D</</il>
16
+ </ul>
17
+ <p class="end">End</p>
18
+ </body>
19
+ </html>
20
+ END
21
+ end
22
+
23
+ before do
24
+ docs = [template('X'), template('Y'), template('Z')]
25
+ @deltoid = Deltoid.new(docs)
26
+ end
27
+
28
+ it 'delta should be correct' do
29
+ actual = @deltoid.delta
30
+ actual.length.should == 3
31
+ actual.should include({
32
+ :index => 0,
33
+ :content => 'X',
34
+ :xpath => '/html/body/ul/li[3]',
35
+ })
36
+ actual.should include({
37
+ :index => 1,
38
+ :content => 'Y',
39
+ :xpath => '/html/body/ul/li[3]',
40
+ })
41
+ actual.should include({
42
+ :index => 2,
43
+ :content => 'Z',
44
+ :xpath => '/html/body/ul/li[3]',
45
+ })
46
+ end
47
+
48
+ end
data/spec/5_spec.rb ADDED
@@ -0,0 +1,47 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe '3 documents, 3 <li>, 1 different class' do
4
+ include Unindentable
5
+
6
+ def template(x = nil)
7
+ unindent <<-END
8
+ <html>
9
+ <body>
10
+ <p>Begin</p>
11
+ <ul class="list">
12
+ <li>A</li>
13
+ <li#{x ? " #{x}" : ""}>B</li>
14
+ <li>C</li>
15
+ </ul>
16
+ <p>End</p>
17
+ </body>
18
+ </html>
19
+ END
20
+ end
21
+
22
+ before do
23
+ docs = [template, template("class='special'"), template]
24
+ @deltoid = Deltoid.new(docs)
25
+ end
26
+
27
+ it 'delta should be correct' do
28
+ actual = @deltoid.delta
29
+ actual.length.should == 3
30
+ actual.should include({
31
+ :index => 0,
32
+ :content => 'B',
33
+ :xpath => '/html/body/ul/li[2]',
34
+ })
35
+ actual.should include({
36
+ :index => 1,
37
+ :content => 'B',
38
+ :xpath => '/html/body/ul/li[2]',
39
+ })
40
+ actual.should include({
41
+ :index => 2,
42
+ :content => 'B',
43
+ :xpath => '/html/body/ul/li[2]',
44
+ })
45
+ end
46
+
47
+ end
@@ -0,0 +1,3 @@
1
+ require File.expand_path('../../lib/deltoid', __FILE__)
2
+ require 'rspec'
3
+ require 'unindentable'
metadata ADDED
@@ -0,0 +1,233 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deltoid
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - David James
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-15 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ type: :runtime
23
+ prerelease: false
24
+ name: nokogiri
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 7
31
+ segments:
32
+ - 1
33
+ - 4
34
+ version: "1.4"
35
+ requirement: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ type: :development
38
+ prerelease: false
39
+ name: bundler
40
+ version_requirements: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 15
46
+ segments:
47
+ - 1
48
+ - 0
49
+ version: "1.0"
50
+ requirement: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ type: :development
53
+ prerelease: false
54
+ name: jeweler
55
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 5
61
+ segments:
62
+ - 1
63
+ - 5
64
+ version: "1.5"
65
+ requirement: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ type: :development
68
+ prerelease: false
69
+ name: rspec
70
+ version_requirements: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ hash: 1
76
+ segments:
77
+ - 2
78
+ - 1
79
+ version: "2.1"
80
+ requirement: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ type: :development
83
+ prerelease: false
84
+ name: unindentable
85
+ version_requirements: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirement: *id005
95
+ - !ruby/object:Gem::Dependency
96
+ type: :runtime
97
+ prerelease: false
98
+ name: nokogiri
99
+ version_requirements: &id006 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ~>
103
+ - !ruby/object:Gem::Version
104
+ hash: 7
105
+ segments:
106
+ - 1
107
+ - 4
108
+ version: "1.4"
109
+ requirement: *id006
110
+ - !ruby/object:Gem::Dependency
111
+ type: :development
112
+ prerelease: false
113
+ name: bundler
114
+ version_requirements: &id007 !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ~>
118
+ - !ruby/object:Gem::Version
119
+ hash: 15
120
+ segments:
121
+ - 1
122
+ - 0
123
+ version: "1.0"
124
+ requirement: *id007
125
+ - !ruby/object:Gem::Dependency
126
+ type: :development
127
+ prerelease: false
128
+ name: jeweler
129
+ version_requirements: &id008 !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ~>
133
+ - !ruby/object:Gem::Version
134
+ hash: 5
135
+ segments:
136
+ - 1
137
+ - 5
138
+ version: "1.5"
139
+ requirement: *id008
140
+ - !ruby/object:Gem::Dependency
141
+ type: :development
142
+ prerelease: false
143
+ name: rspec
144
+ version_requirements: &id009 !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ~>
148
+ - !ruby/object:Gem::Version
149
+ hash: 1
150
+ segments:
151
+ - 2
152
+ - 1
153
+ version: "2.1"
154
+ requirement: *id009
155
+ - !ruby/object:Gem::Dependency
156
+ type: :development
157
+ prerelease: false
158
+ name: unindentable
159
+ version_requirements: &id010 !ruby/object:Gem::Requirement
160
+ none: false
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ hash: 3
165
+ segments:
166
+ - 0
167
+ version: "0"
168
+ requirement: *id010
169
+ description: Deltoid diffs HTML documents using a relatively simple N-way algorithm. It reports deltas as an array of hashes, where each hash contains :content, :xpath, and :index keys.
170
+ email: davidcjames@gmail.com
171
+ executables: []
172
+
173
+ extensions: []
174
+
175
+ extra_rdoc_files:
176
+ - LICENSE.txt
177
+ - README.md
178
+ files:
179
+ - .document
180
+ - Gemfile
181
+ - Gemfile.lock
182
+ - LICENSE.txt
183
+ - README.md
184
+ - Rakefile
185
+ - VERSION
186
+ - lib/deltoid.rb
187
+ - spec/1_spec.rb
188
+ - spec/2_spec.rb
189
+ - spec/3_spec.rb
190
+ - spec/4_spec.rb
191
+ - spec/5_spec.rb
192
+ - spec/spec_helper.rb
193
+ has_rdoc: true
194
+ homepage: http://github.com/djsun/deltoid
195
+ licenses:
196
+ - MIT
197
+ post_install_message:
198
+ rdoc_options: []
199
+
200
+ require_paths:
201
+ - lib
202
+ required_ruby_version: !ruby/object:Gem::Requirement
203
+ none: false
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ hash: 3
208
+ segments:
209
+ - 0
210
+ version: "0"
211
+ required_rubygems_version: !ruby/object:Gem::Requirement
212
+ none: false
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ hash: 3
217
+ segments:
218
+ - 0
219
+ version: "0"
220
+ requirements: []
221
+
222
+ rubyforge_project:
223
+ rubygems_version: 1.3.7
224
+ signing_key:
225
+ specification_version: 3
226
+ summary: Deltoid finds differences between two or more HTML documents.
227
+ test_files:
228
+ - spec/1_spec.rb
229
+ - spec/2_spec.rb
230
+ - spec/3_spec.rb
231
+ - spec/4_spec.rb
232
+ - spec/5_spec.rb
233
+ - spec/spec_helper.rb