smart_diff 0.0.1
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.
- data/README.md +38 -0
- data/Rakefile +13 -0
- data/bin/smart_diff +69 -0
- data/doc/Htmlize.html +1209 -0
- data/doc/SmartDiff.html +790 -0
- data/doc/Tag.html +484 -0
- data/doc/Utils.html +370 -0
- data/doc/_index.html +149 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +338 -0
- data/doc/file.README.html +127 -0
- data/doc/file_list.html +55 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +127 -0
- data/doc/js/app.js +214 -0
- data/doc/js/full_list.js +178 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +250 -0
- data/doc/top-level-namespace.html +114 -0
- data/example/bar.rb +52 -0
- data/example/foo.rb +51 -0
- data/foo.rb-bar.rb.html +498 -0
- data/lib/smart_diff/htmlize.rb +181 -0
- data/lib/smart_diff/utils.rb +29 -0
- data/lib/smart_diff.rb +49 -0
- data/spec/smart_diff/htmlize_spec.rb +33 -0
- data/spec/smart_diff/utils_spec.rb +34 -0
- data/spec/smart_diff_spec.rb +31 -0
- data/web/diff.css +96 -0
- data/web/nav.js +275 -0
- metadata +133 -0
data/lib/smart_diff.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require "jruby-parser"
|
2
|
+
require "pathname"
|
3
|
+
require "jruby-parser.jar"
|
4
|
+
|
5
|
+
import org.jrubyparser.util.diff.NodeDiff
|
6
|
+
|
7
|
+
class SmartDiff
|
8
|
+
attr_accessor :file_one, :file_two, :code_one, :code_two, :node_diff
|
9
|
+
|
10
|
+
|
11
|
+
#
|
12
|
+
# Create a SmartDiff object which will create diff of two source
|
13
|
+
# files based on AST generated by JRubyParser.
|
14
|
+
#
|
15
|
+
# @param file_one [String] The path to the first source file.
|
16
|
+
# @param file_two [String] The path to the second source file.
|
17
|
+
#
|
18
|
+
# @return [SmartDiff] A Ruby object which holds a reference to a diff.
|
19
|
+
def initialize(file_one, file_two)
|
20
|
+
@file_one = file_one
|
21
|
+
@file_two = file_two
|
22
|
+
@node_diff = diff()
|
23
|
+
end
|
24
|
+
|
25
|
+
def read(file_name)
|
26
|
+
path = Pathname.new(file_name).expand_path
|
27
|
+
if path.exist?
|
28
|
+
File.read path
|
29
|
+
else
|
30
|
+
raise "#{path} not found. Check the path."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse(code_to_parse, file_name)
|
35
|
+
JRubyParser.parse(code_to_parse, { :filename => file_name })
|
36
|
+
end
|
37
|
+
|
38
|
+
def diff()
|
39
|
+
@code_one = read(@file_one)
|
40
|
+
@code_two = read(@file_two)
|
41
|
+
if @code_one && @code_two
|
42
|
+
nodeA = parse(@code_one, @file_one)
|
43
|
+
nodeB = parse(@code_two, @file_two)
|
44
|
+
nd = org.jrubyparser.util.diff.NodeDiff.new(nodeA, @code_one, nodeB, @code_two)
|
45
|
+
nd.deep_diff
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "smart_diff/htmlize"
|
2
|
+
|
3
|
+
describe "Htmlize" do
|
4
|
+
|
5
|
+
it "should clear the uid variables" do
|
6
|
+
html = Htmlize.new
|
7
|
+
html.uid_count = 10
|
8
|
+
html.uid_hash = { :foo => "bar", :baz => "qux" }
|
9
|
+
html.clear_uid()
|
10
|
+
html.uid_count.should == -1
|
11
|
+
html.uid_hash.should == {}
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should increment the uid_count" do
|
15
|
+
html = Htmlize.new
|
16
|
+
html.uid_count = 5
|
17
|
+
html.uid("banana")
|
18
|
+
html.uid_count.should == 6
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should set the hash if it wasn't previously set" do
|
22
|
+
html = Htmlize.new
|
23
|
+
html.uid(:cow)
|
24
|
+
html.uid_hash.should have_key(:cow)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return the entry for a previously set hash" do
|
28
|
+
html = Htmlize.new
|
29
|
+
html.uid_hash = { banana: "cow" }
|
30
|
+
html.uid(:banana).should =~ /cow/
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "smart_diff/utils"
|
2
|
+
|
3
|
+
class Position
|
4
|
+
def start_offset
|
5
|
+
600
|
6
|
+
end
|
7
|
+
|
8
|
+
def end_offset
|
9
|
+
750
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestNode
|
14
|
+
def position
|
15
|
+
Position.new
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "Utils" do
|
21
|
+
include Utils
|
22
|
+
|
23
|
+
it "should return a nodes start position" do
|
24
|
+
tn = TestNode.new
|
25
|
+
start = node_start(tn)
|
26
|
+
start.should == 600
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return a nodes end position" do
|
30
|
+
tn = TestNode.new
|
31
|
+
nd_end = node_end(tn)
|
32
|
+
nd_end.should == 750
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "smart_diff"
|
2
|
+
|
3
|
+
describe "SmartDiff" do
|
4
|
+
before(:each) do
|
5
|
+
@rd = SmartDiff.new 'example/foo.rb', 'example/bar.rb'
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should take two filenames" do
|
9
|
+
@rd.file_one.should == 'example/foo.rb'
|
10
|
+
@rd.file_two.should == 'example/bar.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should read two files in as strings" do
|
14
|
+
@rd.read(@rd.file_one).class.should == String
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should raise an exception if the file does not exist" do
|
18
|
+
expect { @rd.read('foo/foofile.rb') }.to raise_error(StandardError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should parse the files into ASTs" do
|
22
|
+
code_for_parse = @rd.read(@rd.file_one)
|
23
|
+
@rd.parse(code_for_parse, @rd.file_one).instance_of?(org.jrubyparser.ast.RootNode).should be(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should create a diff of the two ASTs" do
|
27
|
+
@rd.node_diff.size.should >= 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
data/web/diff.css
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
.d { /* deleted */
|
2
|
+
border: solid 1px #CC929A;
|
3
|
+
border-radius: 3px;
|
4
|
+
background-color: #FCBFBA;
|
5
|
+
}
|
6
|
+
|
7
|
+
.i { /* inserted */
|
8
|
+
border: solid 1px #73BE73;
|
9
|
+
border-radius: 3px;
|
10
|
+
background-color: #98FB98;
|
11
|
+
}
|
12
|
+
|
13
|
+
.c { /* changed */
|
14
|
+
border: solid 1px #8AADB8;
|
15
|
+
background-color: LightBlue;
|
16
|
+
border-radius: 3px;
|
17
|
+
cursor: pointer;
|
18
|
+
}
|
19
|
+
|
20
|
+
.m { /* moved */
|
21
|
+
border: solid 1px #A9A9A9;
|
22
|
+
border-radius: 3px;
|
23
|
+
cursor: crosshair;
|
24
|
+
}
|
25
|
+
|
26
|
+
.mc {
|
27
|
+
border: solid 1px LightPink;
|
28
|
+
background-color: LightBlue;
|
29
|
+
cursor: pointer;
|
30
|
+
}
|
31
|
+
|
32
|
+
.u { /* unchanged */
|
33
|
+
border: solid 1px #A9A9A9;
|
34
|
+
border-radius: 4px;
|
35
|
+
cursor: crosshair;
|
36
|
+
}
|
37
|
+
|
38
|
+
span.lineno {
|
39
|
+
color: lightgrey;
|
40
|
+
-webkit-user-select: none;
|
41
|
+
-moz-user-select: none;
|
42
|
+
}
|
43
|
+
|
44
|
+
span.keyword {
|
45
|
+
/* color: #007070; */
|
46
|
+
font-weight: 700;
|
47
|
+
}
|
48
|
+
|
49
|
+
div.line {
|
50
|
+
}
|
51
|
+
|
52
|
+
div.src {
|
53
|
+
width:48%;
|
54
|
+
height:98%;
|
55
|
+
overflow:scroll;
|
56
|
+
float:left;
|
57
|
+
padding:0.5%;
|
58
|
+
border: solid 2px LightGrey;
|
59
|
+
border-radius: 5px;
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
div.stats {
|
64
|
+
border: solid 1px grey;
|
65
|
+
z-index: 1000;
|
66
|
+
width: 80%;
|
67
|
+
padding-left: 5%;
|
68
|
+
}
|
69
|
+
|
70
|
+
pre.stats {
|
71
|
+
color: grey;
|
72
|
+
-webkit-user-select: none;
|
73
|
+
-moz-user-select: none;
|
74
|
+
}
|
75
|
+
|
76
|
+
pre {
|
77
|
+
line-height: 200%;
|
78
|
+
}
|
79
|
+
|
80
|
+
p {
|
81
|
+
line-height: 200%;
|
82
|
+
}
|
83
|
+
|
84
|
+
::-webkit-scrollbar {
|
85
|
+
width: 10px;
|
86
|
+
}
|
87
|
+
|
88
|
+
::-webkit-scrollbar-track {
|
89
|
+
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
90
|
+
border-radius: 10px;
|
91
|
+
}
|
92
|
+
|
93
|
+
::-webkit-scrollbar-thumb {
|
94
|
+
border-radius: 10px;
|
95
|
+
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
|
96
|
+
}
|
data/web/nav.js
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
// convenience function for document.getElementById().
|
2
|
+
window['$']=function(a){return document.getElementById(a)};
|
3
|
+
|
4
|
+
|
5
|
+
/////////////////////// debug flag ////////////////////////
|
6
|
+
var debug = false;
|
7
|
+
|
8
|
+
|
9
|
+
/////////////////////// adjustable parameters //////////////////
|
10
|
+
var minStep = 10;
|
11
|
+
var nSteps = 30;
|
12
|
+
var stepInterval = 10;
|
13
|
+
var blockRange = 5; // how far consider one page blocked
|
14
|
+
var nodeHLColor = '#C9B0A9';
|
15
|
+
var lineHLColor = '#FFFF66';
|
16
|
+
var lineBlockedColor = '#E9AB17';
|
17
|
+
var bgColor = '';
|
18
|
+
var bodyBlockedColor = '#FAF0E6';
|
19
|
+
|
20
|
+
|
21
|
+
///////////////////////// globals ////////////////////////
|
22
|
+
var eventCount = { 'left' : 0, 'right' : 0};
|
23
|
+
var moving = false;
|
24
|
+
var matchId1 = 'leftstart';
|
25
|
+
var matchId2 = 'rightstart';
|
26
|
+
var matchLineId1 = -1;
|
27
|
+
var matchLineId2 = -1;
|
28
|
+
var cTimeout;
|
29
|
+
|
30
|
+
|
31
|
+
///////////////////////// utilities ///////////////////////
|
32
|
+
|
33
|
+
// No Math.sign() in JS?
|
34
|
+
function sign(x) {
|
35
|
+
if (x > 0) {
|
36
|
+
return 1;
|
37
|
+
} else if (x < 0) {
|
38
|
+
return -1;
|
39
|
+
} else {
|
40
|
+
return 0;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
function log(msg) {
|
46
|
+
if (debug) {
|
47
|
+
console.log(msg);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
function elementPosition(id) {
|
54
|
+
obj = $(id);
|
55
|
+
var curleft = 0, curtop = 0;
|
56
|
+
|
57
|
+
if (obj && obj.offsetParent) {
|
58
|
+
curleft = obj.offsetLeft;
|
59
|
+
curtop = obj.offsetTop;
|
60
|
+
|
61
|
+
while (obj = obj.offsetParent) {
|
62
|
+
curleft += obj.offsetLeft;
|
63
|
+
curtop += obj.offsetTop;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
return { x: curleft, y: curtop };
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
/*
|
72
|
+
* Scroll the window to relative position, detecting blocking positions.
|
73
|
+
*/
|
74
|
+
function scrollWithBlockCheck(container, distX, distY) {
|
75
|
+
var oldTop = container.scrollTop;
|
76
|
+
var oldLeft = container.scrollLeft;
|
77
|
+
|
78
|
+
container.scrollTop += distY; // the ONLY place for actual scrolling
|
79
|
+
container.scrollLeft += distX;
|
80
|
+
|
81
|
+
var actualX = container.scrollLeft - oldLeft;
|
82
|
+
var actualY = container.scrollTop - oldTop;
|
83
|
+
log("distY=" + distY + ", actualY=" + actualY);
|
84
|
+
log("distX=" + distX + ", actualX=" + actualX);
|
85
|
+
|
86
|
+
// extra leewaw here because Chrome scrolling is horribly inacurate
|
87
|
+
if ((Math.abs(distX) > blockRange && actualX === 0)
|
88
|
+
|| Math.abs(distY) > blockRange && actualY === 0) {
|
89
|
+
log("blocked");
|
90
|
+
container.style.backgroundColor = bodyBlockedColor;
|
91
|
+
return true;
|
92
|
+
} else {
|
93
|
+
eventCount[container.id] += 1;
|
94
|
+
container.style.backgroundColor = bgColor;
|
95
|
+
return false;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
function getContainer(elm) {
|
101
|
+
while (elm && elm.tagName !== 'DIV') {
|
102
|
+
elm = elm.parentElement || elm.parentNode;
|
103
|
+
}
|
104
|
+
return elm;
|
105
|
+
}
|
106
|
+
|
107
|
+
|
108
|
+
/*
|
109
|
+
* timed animation function for scrolling the current window
|
110
|
+
*/
|
111
|
+
function matchWindow(linkId, targetId, n)
|
112
|
+
{
|
113
|
+
moving = true;
|
114
|
+
|
115
|
+
var link = $(linkId);
|
116
|
+
var target = $(targetId);
|
117
|
+
var linkContainer = getContainer(link);
|
118
|
+
var targetContainer = getContainer(target);
|
119
|
+
|
120
|
+
var linkPos = elementPosition(linkId).y - linkContainer.scrollTop;
|
121
|
+
var targetPos = elementPosition(targetId).y - targetContainer.scrollTop;
|
122
|
+
var distY = targetPos - linkPos;
|
123
|
+
var distX = linkContainer.scrollLeft - targetContainer.scrollLeft;
|
124
|
+
|
125
|
+
|
126
|
+
log("matching window... " + n + " distY=" + distY + " distX=" + distX);
|
127
|
+
|
128
|
+
if (distY === 0 && distX === 0) {
|
129
|
+
clearTimeout(cTimeout);
|
130
|
+
moving = false;
|
131
|
+
} else if (n <= 1) {
|
132
|
+
scrollWithBlockCheck(targetContainer, distX, distY);
|
133
|
+
moving = false;
|
134
|
+
} else {
|
135
|
+
var stepSize = Math.floor(Math.abs(distY) / n);
|
136
|
+
actualMinStep = Math.min(minStep, Math.abs(distY));
|
137
|
+
if (Math.abs(stepSize) < minStep) {
|
138
|
+
var step = actualMinStep * sign(distY);
|
139
|
+
} else {
|
140
|
+
var step = stepSize * sign(distY);
|
141
|
+
}
|
142
|
+
var blocked = scrollWithBlockCheck(targetContainer, distX, step);
|
143
|
+
var rest = Math.floor(distY / step) - 1;
|
144
|
+
log("blocked?" + blocked + ", rest steps=" + rest);
|
145
|
+
if (!blocked) {
|
146
|
+
cTimeout = setTimeout(function () {
|
147
|
+
return matchWindow(linkId, targetId, rest);
|
148
|
+
}, stepInterval);
|
149
|
+
} else {
|
150
|
+
clearTimeout(cTimeout);
|
151
|
+
moving = false;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
|
157
|
+
function showArrow(linkId, targetId)
|
158
|
+
{
|
159
|
+
var link = $(linkId);
|
160
|
+
var target = $(targetId);
|
161
|
+
var linkContainer = getContainer(link);
|
162
|
+
var targetContainer = getContainer(target);
|
163
|
+
|
164
|
+
var linkPos = elementPosition(linkId).y - linkContainer.scrollTop;
|
165
|
+
var targetPos = elementPosition(targetId).y - targetContainer.scrollTop;
|
166
|
+
var distY = targetPos - linkPos;
|
167
|
+
var distX = linkContainer.scrollLeft - targetContainer.scrollLeft;
|
168
|
+
|
169
|
+
|
170
|
+
log("targetPos = " + targetPos);
|
171
|
+
}
|
172
|
+
|
173
|
+
|
174
|
+
////////////////////////// highlighting /////////////////////////////
|
175
|
+
|
176
|
+
var highlighted = []
|
177
|
+
function putHighlight(id, color) {
|
178
|
+
var elm = $(id);
|
179
|
+
if (elm !== null) {
|
180
|
+
elm.style.backgroundColor = color;
|
181
|
+
if (color !== bgColor) {
|
182
|
+
highlighted.push(id);
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
|
188
|
+
function clearHighlight() {
|
189
|
+
for (i = 0; i < highlighted.length; i += 1) {
|
190
|
+
putHighlight(highlighted[i], bgColor);
|
191
|
+
}
|
192
|
+
highlighted = [];
|
193
|
+
}
|
194
|
+
|
195
|
+
|
196
|
+
|
197
|
+
/*
|
198
|
+
* Highlight the link, target nodes and their lines,
|
199
|
+
* then start animation to move the other window to match.
|
200
|
+
*/
|
201
|
+
function highlight(me, linkId, targetId)
|
202
|
+
{
|
203
|
+
if (me.id === 'left') {
|
204
|
+
matchId1 = linkId;
|
205
|
+
matchId2 = targetId;
|
206
|
+
} else {
|
207
|
+
matchId1 = targetId;
|
208
|
+
matchId2 = linkId;
|
209
|
+
}
|
210
|
+
|
211
|
+
clearHighlight();
|
212
|
+
|
213
|
+
putHighlight(linkId, nodeHLColor);
|
214
|
+
putHighlight(targetId, nodeHLColor);
|
215
|
+
}
|
216
|
+
|
217
|
+
|
218
|
+
function instantMoveOtherWindow (me) {
|
219
|
+
log("me=" + me.id + ", eventcount=" + eventCount[me.id]);
|
220
|
+
log("matchId1=" + matchId1 + ", matchId2=" + matchId2);
|
221
|
+
|
222
|
+
me.style.backgroundColor = bgColor;
|
223
|
+
|
224
|
+
if (!moving && eventCount[me.id] === 0) {
|
225
|
+
if (me.id === 'left') {
|
226
|
+
matchWindow(matchId1, matchId2, 1);
|
227
|
+
} else {
|
228
|
+
matchWindow(matchId2, matchId1, 1);
|
229
|
+
}
|
230
|
+
}
|
231
|
+
if (eventCount[me.id] > 0) {
|
232
|
+
eventCount[me.id] -= 1;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
|
237
|
+
function getTarget(x){
|
238
|
+
x = x || window.event;
|
239
|
+
return x.target || x.srcElement;
|
240
|
+
}
|
241
|
+
|
242
|
+
|
243
|
+
window.onload =
|
244
|
+
function (e) {
|
245
|
+
var tags = document.getElementsByTagName("A")
|
246
|
+
for (var i = 0; i < tags.length; i++) {
|
247
|
+
tags[i].onmouseover =
|
248
|
+
function (e) {
|
249
|
+
var t = getTarget(e)
|
250
|
+
var lid = t.id
|
251
|
+
var tid = t.getAttribute('tid')
|
252
|
+
var container = getContainer(t)
|
253
|
+
highlight(container, lid, tid)
|
254
|
+
showArrow(lid, tid)
|
255
|
+
}
|
256
|
+
tags[i].onclick =
|
257
|
+
function (e) {
|
258
|
+
var t = getTarget(e)
|
259
|
+
var lid = t.id
|
260
|
+
var tid = t.getAttribute('tid')
|
261
|
+
var container = getContainer(t)
|
262
|
+
highlight(container, lid, tid)
|
263
|
+
matchWindow(lid, tid, nSteps)
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
tags = document.getElementsByTagName("DIV")
|
268
|
+
for (var i = 0; i < tags.length; i++) {
|
269
|
+
tags[i].onscroll =
|
270
|
+
function (e) {
|
271
|
+
instantMoveOtherWindow(getTarget(e))
|
272
|
+
}
|
273
|
+
}
|
274
|
+
|
275
|
+
}
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smart_diff
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Eric West
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: jruby-parser
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.5.1
|
21
|
+
none: false
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.5.1
|
27
|
+
none: false
|
28
|
+
prerelease: false
|
29
|
+
type: :runtime
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
none: false
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
none: false
|
44
|
+
prerelease: false
|
45
|
+
type: :development
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: yard
|
48
|
+
version_requirements: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
none: false
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
none: false
|
60
|
+
prerelease: false
|
61
|
+
type: :development
|
62
|
+
description: Create Semantic Diffs of Ruby source code based on the AST.
|
63
|
+
email: esw9999@gmail.com
|
64
|
+
executables:
|
65
|
+
- smart_diff
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- doc/Htmlize.html
|
70
|
+
- doc/SmartDiff.html
|
71
|
+
- doc/Tag.html
|
72
|
+
- doc/Utils.html
|
73
|
+
- doc/_index.html
|
74
|
+
- doc/class_list.html
|
75
|
+
- doc/css/common.css
|
76
|
+
- doc/css/full_list.css
|
77
|
+
- doc/css/style.css
|
78
|
+
- doc/file.README.html
|
79
|
+
- doc/file_list.html
|
80
|
+
- doc/frames.html
|
81
|
+
- doc/index.html
|
82
|
+
- doc/js/app.js
|
83
|
+
- doc/js/full_list.js
|
84
|
+
- doc/js/jquery.js
|
85
|
+
- doc/method_list.html
|
86
|
+
- doc/top-level-namespace.html
|
87
|
+
- example/bar.rb
|
88
|
+
- example/foo.rb
|
89
|
+
- lib/smart_diff.rb
|
90
|
+
- lib/smart_diff/htmlize.rb
|
91
|
+
- lib/smart_diff/utils.rb
|
92
|
+
- spec/smart_diff/htmlize_spec.rb
|
93
|
+
- spec/smart_diff/utils_spec.rb
|
94
|
+
- spec/smart_diff_spec.rb
|
95
|
+
- web/diff.css
|
96
|
+
- web/nav.js
|
97
|
+
- bin/smart_diff
|
98
|
+
- README.md
|
99
|
+
- foo.rb-bar.rb.html
|
100
|
+
- Rakefile
|
101
|
+
homepage: http://github.com/edubkendo/smart_diff.git
|
102
|
+
licenses:
|
103
|
+
- GPL
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
segments:
|
113
|
+
- 0
|
114
|
+
hash: 2
|
115
|
+
version: '0'
|
116
|
+
none: false
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
none: false
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.24
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: Ruby clone of psydiff
|
129
|
+
test_files:
|
130
|
+
- spec/smart_diff/htmlize_spec.rb
|
131
|
+
- spec/smart_diff/utils_spec.rb
|
132
|
+
- spec/smart_diff_spec.rb
|
133
|
+
has_rdoc: yard
|