diff_to_html 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ = diff_to_html
2
+
3
+ Ruby library to convert unified diffs like you get from SVN and git to HTML
4
+
5
+ It'a fork of https://github.com/artemv/diff_to_html.rb to use as a dependency in gem specs of other gems through Rubygems.org hosting.
6
+
7
+ It's furthermore based on code from http://gurge.com/blog/2006/10/03/subversion-diff-viewer-cgi-in-ruby (thanks Adam
8
+ Doppelt!), adopted lightly to support multifile diffs and to have more familiar output. It definitely have
9
+ things to improve, so contribution/patches are very welcome.
10
+
11
+ * install the gem:
12
+
13
+ gem install diff_to_html
14
+
15
+ * go to gem's 'examples' dir and run 'ruby test.rb >out.html' -
16
+ this will get diff from sample 'svn diff' and generate out.html. Resulting html is linked to diff.css in 'examples' directory - you'll need
17
+ to copy it to your project's dir to use it.
18
+
19
+ * To use in Rails project:
20
+
21
+ require 'diff_to_html'
22
+ diff = `cat #{File.join(File.dirname(__FILE__), 'diff.git')}`
23
+ converter = DiffToHtml::GitConverter.new #there's also DiffToHtml::SvnConverter
24
+ puts converter.composite_to_html(diff)
25
+
26
+ * to use in any Ruby program:
27
+
28
+ require 'rubygems'
29
+ require 'diff_to_html'
30
+ ...
31
+
32
+ == License
33
+
34
+ diff_to_html is released under the MIT license.
35
+
36
+ == Authors and credits
37
+
38
+ Authors:: Artem Vasiliev
39
+ Original code:: Adam Doppelt, http://gurge.com/blog/2006/10/03/subversion-diff-viewer-cgi-in-ruby
40
+
@@ -0,0 +1,6 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module DiffToHtml
3
+ autoload :Converter, File.expand_path('diff_to_html/converter', File.dirname(__FILE__))
4
+ autoload :SvnConverter, File.expand_path('diff_to_html/svn_converter', File.dirname(__FILE__))
5
+ autoload :GitConverter, File.expand_path('diff_to_html/git_converter', File.dirname(__FILE__))
6
+ end
@@ -0,0 +1,230 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'cgi'
3
+
4
+ module DiffToHtml
5
+ class Converter
6
+ attr_accessor :file_prefix
7
+
8
+ def composite_to_html(composite_diff)
9
+ diffs_to_html get_diffs(composite_diff)
10
+ end
11
+
12
+ def diffs_to_html(diffs)
13
+ result = '<ul class="diff">'
14
+ @filenum = 0
15
+
16
+ diffs.each do |file_map|
17
+ result << get_single_file_diff(file_map[:filename], file_map[:file])
18
+ @filenum += 1
19
+ end
20
+
21
+ result << '</ul>'
22
+ result
23
+ end
24
+
25
+ def get_single_file_diff(file_name, diff_file)
26
+ result = ""
27
+ diff = diff_file.split("\n")
28
+ diff, line = shift_until_first_line(diff)
29
+
30
+ if line =~ /^---/
31
+ result << begin_file(file_name)
32
+ result << get_single_file_diff_body(diff)
33
+ result << "</li>"
34
+ else
35
+ #"<div class='error'>#{line}</div>"
36
+ result =%Q{<li><h2><a name="F#{@filenum}" href="#F#{@filenum}">#{file_name}</a></h2>#{line}</li>}
37
+ end
38
+
39
+ result
40
+ end
41
+
42
+ def get_single_file_diff_body(diff)
43
+ @last_op, @left, @right = ' ', [], []
44
+
45
+ if diff.is_a? String
46
+ diff = diff.split("\n")
47
+ diff, line = shift_until_first_line(diff)
48
+ end
49
+
50
+ diff.shift #+++
51
+
52
+ result = %Q{
53
+ <table class='diff'>
54
+ <colgroup>
55
+ <col class="lineno"/>
56
+ <col class="lineno"/>
57
+ <col class="content"/>
58
+ </colgroup>
59
+ }
60
+
61
+ range = diff.shift
62
+ left_ln, right_ln = range_info(range)
63
+ result << range_row(range)
64
+
65
+ diff.each do |line|
66
+ op = line[0,1]
67
+ line = line[1..-1] || ''
68
+
69
+ if op == '\\'
70
+ line = op + line
71
+ op = ' '
72
+ end
73
+
74
+ if ((@last_op != ' ' and op == ' ') or (@last_op == ' ' and op != ' '))
75
+ left_ln, right_ln = flush_changes(result, left_ln, right_ln)
76
+ end
77
+
78
+ # truncate and escape
79
+ line = CGI.escapeHTML(line)
80
+
81
+ case op
82
+ when ' '
83
+ @left.push(line)
84
+ @right.push(line)
85
+ when '-' then @left.push(line)
86
+ when '+' then @right.push(line)
87
+ when '@'
88
+ range = '@' + line
89
+ flush_changes(result, left_ln, right_ln)
90
+ left_ln, right_ln = range_info(range)
91
+ result << range_row(range)
92
+ else
93
+ flush_changes(result, left_ln, right_ln)
94
+ result << "</table></li>"
95
+ break
96
+ end
97
+ @last_op = op
98
+ end
99
+
100
+ flush_changes(result, left_ln, right_ln)
101
+ result << "</table>"
102
+
103
+ result
104
+ end
105
+
106
+ def file_header_pattern
107
+ raise "Method to be implemented in VCS-specific class"
108
+ end
109
+
110
+ private
111
+
112
+ def get_diffs(composite_diff)
113
+ pattern = file_header_pattern
114
+ files = composite_diff.split(pattern)
115
+ headers = composite_diff.scan(pattern) #huh can't find a way to get both at once
116
+ files.shift if files[0] == '' #first one is junk usually
117
+ result = []
118
+ i = 0
119
+
120
+ files.each do |file|
121
+ result << {:filename => "#{file_prefix}#{get_filename(headers[i])}", :file => file}
122
+ i += 1
123
+ end
124
+
125
+ result
126
+ end
127
+
128
+ def shift_until_first_line(diff)
129
+ diff.shift if diff.first.match(/#index/)
130
+
131
+ line = nil
132
+
133
+ while line !~ /^---/ && !diff.empty?
134
+ line = diff.shift
135
+ end
136
+
137
+ [diff, line]
138
+ end
139
+
140
+ def begin_file(file)
141
+ result = %Q{
142
+ <li>
143
+ <h2><a name="F#{@filenum}" href="#F#{@filenum}">#{file}</a></h2>
144
+ }
145
+
146
+ result
147
+ end
148
+
149
+ def range_info(range)
150
+ left_ln, right_ln = range.gsub(/(@|-|\+)+/, '').strip.split(' ').map{|ln| ln.split(',')[0]}
151
+
152
+ begin
153
+ return Integer(left_ln), Integer(right_ln)
154
+ rescue Exception => e
155
+ raise NotImplementedError.new(
156
+ e.class.name + " (#{e.message}): " + range.inspect + " => [#{left_ln.inspect}, #{right_ln.inspect}]"
157
+ )
158
+ end
159
+ end
160
+
161
+ def range_row(range)
162
+ "<tr class='range'><td>...</td><td>...</td><td>#{range}</td></tr>"
163
+ end
164
+
165
+ def flush_changes(result, left_ln, right_ln)
166
+ x, left_ln, right_ln = get_diff_row(left_ln, right_ln)
167
+ result << x
168
+ @left.clear
169
+ @right.clear
170
+ return left_ln, right_ln
171
+ end
172
+
173
+ #
174
+ # helper for building the next row in the diff
175
+ #
176
+ def get_diff_row(left_ln, right_ln)
177
+ result = []
178
+ if @left.length > 0 or @right.length > 0
179
+ modified = (@last_op != ' ')
180
+
181
+ if modified
182
+ left_class = " class='r'"
183
+ right_class = " class='a'"
184
+ result << "<tbody class='mod'>"
185
+ else
186
+ left_class = right_class = ''
187
+ end
188
+
189
+ result << @left.map do |line|
190
+ x = "<tr#{left_class}>#{ln_cell(left_ln, 'l')}"
191
+
192
+ if modified
193
+ x += ln_cell(nil)
194
+ else
195
+ x += ln_cell(right_ln, 'r')
196
+ right_ln += 1
197
+ end
198
+
199
+ x += "<td>#{line}</td></tr>"
200
+
201
+ left_ln += 1
202
+
203
+ x
204
+ end
205
+
206
+ if modified
207
+ result << @right.map do |line|
208
+ x = "<tr#{right_class}>#{ln_cell(nil)}#{ln_cell(right_ln, 'r')}<td>#{line}</td></tr>"
209
+ right_ln += 1
210
+ x
211
+ end
212
+
213
+ result << "</tbody>"
214
+ end
215
+ end
216
+
217
+ return result.join("\n"), left_ln, right_ln
218
+ end
219
+
220
+ def ln_cell(ln, side = nil)
221
+ anchor = "f#{@filenum}#{side}#{ln}"
222
+ result = "<td class = 'ln'>"
223
+ result += "<a name='#{anchor}' href='##{anchor}'>" if ln
224
+ result += "#{ln}"
225
+ result += "</a>" if ln
226
+ result += "</td>"
227
+ result
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module DiffToHtml
3
+ class GitConverter < Converter
4
+ def file_header_pattern
5
+ /^diff --git.+/
6
+ end
7
+
8
+ def get_filename(file_diff)
9
+ match = (file_diff =~ / b\/(.+)/)
10
+ raise "not matched!" if !match
11
+ $1
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module DiffToHtml
3
+ class SvnConverter < Converter
4
+ def file_header_pattern
5
+ /^Index: .+/
6
+ end
7
+
8
+ def get_filename(header)
9
+ match = (header =~ /^Index: (.+)/) #if we use this pattern file_header_pattern files split doesn't work
10
+ raise "header '#{header}' not matched!" if !match
11
+ $1
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module DiffToHtml
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: diff_to_html
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Adam Doppelt
9
+ - Artem Vasiliev
10
+ - Mathias Gawlista
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2013-05-13 00:00:00.000000000 Z
15
+ dependencies: []
16
+ description: Generates HTML view of given unified diff
17
+ email: gawlista@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files:
21
+ - README.rdoc
22
+ files:
23
+ - README.rdoc
24
+ - lib/diff_to_html/converter.rb
25
+ - lib/diff_to_html/git_converter.rb
26
+ - lib/diff_to_html/svn_converter.rb
27
+ - lib/diff_to_html/version.rb
28
+ - lib/diff_to_html.rb
29
+ homepage: http://github.com/applicat/diff_to_html
30
+ licenses:
31
+ - MIT
32
+ post_install_message:
33
+ rdoc_options:
34
+ - --main
35
+ - README.rdoc
36
+ - --inline-source
37
+ - --charset=UTF-8
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 1.8.24
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: Unified diff to HTML converter
58
+ test_files: []