coopy 0.6.4.1 → 1.0.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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.md +22 -0
  7. data/README.md +59 -0
  8. data/Rakefile +4 -6
  9. data/coopy.gemspec +26 -0
  10. data/lib/coopy.rb +32 -175
  11. data/lib/coopy/alignment.rb +260 -0
  12. data/lib/coopy/bag.rb +17 -0
  13. data/lib/coopy/cell_info.rb +24 -0
  14. data/lib/coopy/change_type.rb +10 -0
  15. data/lib/coopy/compare_flags.rb +62 -0
  16. data/lib/coopy/compare_table.rb +327 -0
  17. data/lib/coopy/coopy.rb +22 -0
  18. data/lib/coopy/cross_match.rb +10 -0
  19. data/lib/coopy/csv_table.rb +51 -0
  20. data/lib/coopy/diff_render.rb +307 -0
  21. data/lib/coopy/index.rb +73 -0
  22. data/lib/coopy/index_item.rb +17 -0
  23. data/lib/coopy/index_pair.rb +72 -0
  24. data/lib/coopy/mover.rb +123 -0
  25. data/lib/coopy/ordering.rb +27 -0
  26. data/lib/coopy/row.rb +9 -0
  27. data/lib/coopy/simple_cell.rb +15 -0
  28. data/lib/coopy/simple_table.rb +144 -0
  29. data/lib/coopy/simple_view.rb +36 -0
  30. data/lib/coopy/table.rb +44 -0
  31. data/lib/coopy/table_comparison_state.rb +33 -0
  32. data/lib/coopy/table_diff.rb +634 -0
  33. data/lib/coopy/table_text.rb +14 -0
  34. data/lib/coopy/table_view.rb +31 -0
  35. data/lib/coopy/unit.rb +53 -0
  36. data/lib/coopy/version.rb +3 -0
  37. data/lib/coopy/view.rb +34 -0
  38. data/spec/fixtures/bridges.html +10 -0
  39. data/spec/fixtures/bridges_diff.csv +8 -0
  40. data/spec/fixtures/bridges_new.csv +9 -0
  41. data/spec/fixtures/bridges_old.csv +9 -0
  42. data/spec/fixtures/planetary_bodies.html +22 -0
  43. data/spec/fixtures/planetary_bodies_diff.csv +19 -0
  44. data/spec/fixtures/planetary_bodies_new.csv +20 -0
  45. data/spec/fixtures/planetary_bodies_old.csv +19 -0
  46. data/spec/fixtures/quote_me.csv +10 -0
  47. data/spec/fixtures/quote_me2.csv +11 -0
  48. data/spec/integration/table_diff_spec.rb +57 -0
  49. data/spec/libs/compare_flags_spec.rb +40 -0
  50. data/spec/libs/coopy_spec.rb +14 -0
  51. data/spec/libs/ordering_spec.rb +28 -0
  52. data/spec/libs/unit_spec.rb +31 -0
  53. data/spec/spec_helper.rb +29 -0
  54. metadata +153 -46
  55. data/bin/sqlite_diff +0 -4
  56. data/bin/sqlite_patch +0 -4
  57. data/bin/sqlite_rediff +0 -4
  58. data/lib/coopy/dbi_sql_wrapper.rb +0 -89
  59. data/lib/coopy/diff_apply_sql.rb +0 -35
  60. data/lib/coopy/diff_columns.rb +0 -33
  61. data/lib/coopy/diff_output.rb +0 -21
  62. data/lib/coopy/diff_output_action.rb +0 -34
  63. data/lib/coopy/diff_output_group.rb +0 -40
  64. data/lib/coopy/diff_output_raw.rb +0 -17
  65. data/lib/coopy/diff_output_stats.rb +0 -45
  66. data/lib/coopy/diff_output_table.rb +0 -49
  67. data/lib/coopy/diff_output_tdiff.rb +0 -48
  68. data/lib/coopy/diff_parser.rb +0 -92
  69. data/lib/coopy/diff_render_csv.rb +0 -29
  70. data/lib/coopy/diff_render_html.rb +0 -74
  71. data/lib/coopy/diff_render_log.rb +0 -52
  72. data/lib/coopy/row_change.rb +0 -25
  73. data/lib/coopy/scraperwiki_sql_wrapper.rb +0 -8
  74. data/lib/coopy/scraperwiki_utils.rb +0 -23
  75. data/lib/coopy/sequel_sql_wrapper.rb +0 -73
  76. data/lib/coopy/sql_compare.rb +0 -222
  77. data/lib/coopy/sql_wrapper.rb +0 -34
  78. data/lib/coopy/sqlite_sql_wrapper.rb +0 -143
  79. data/test/test_coopy.rb +0 -126
@@ -0,0 +1,10 @@
1
+ module Coopy
2
+ class CrossMatch
3
+
4
+ attr_accessor :spot_a # integer
5
+ attr_accessor :spot_b # integer
6
+ attr_accessor :item_a # IndexItem
7
+ attr_accessor :item_b # IndexItem
8
+
9
+ end
10
+ end
@@ -0,0 +1,51 @@
1
+ require 'csv'
2
+
3
+ module Coopy
4
+ class CsvTable
5
+
6
+ include Coopy::Table
7
+
8
+ def initialize(csv)
9
+ @csv = csv
10
+ @height = csv.size
11
+ @width = csv[0].size
12
+ end
13
+
14
+ def get_cell(x, y)
15
+ @csv[y][x]
16
+ end
17
+
18
+ def set_cell(x, y, cell)
19
+ @csv[y][x] = cell
20
+ end
21
+
22
+ def get_cell_view
23
+ Coopy::SimpleView.new
24
+ end
25
+
26
+ def is_resizable?
27
+ false
28
+ end
29
+
30
+ def resize(w, h)
31
+ raise NotImplementedError
32
+ end
33
+
34
+ def clear
35
+ @csv = []
36
+ end
37
+
38
+ def insert_or_delete_rows(fate, hfate)
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def insert_or_delete_columns(fate, wfate)
43
+ raise NotImplementedError
44
+ end
45
+
46
+ def trim_blank
47
+ raise NotImplementedError
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,307 @@
1
+ module Coopy
2
+ class DiffRender
3
+
4
+ def initialize
5
+ @text_to_insert = []
6
+ @open = false
7
+ @pretty_arrows = true
8
+ end
9
+
10
+ def use_pretty_arrows(flag)
11
+ @pretty_arrows = flag
12
+ end
13
+
14
+ def insert(str)
15
+ @text_to_insert.push(str)
16
+ end
17
+
18
+ def begin_table()
19
+ insert("<table>\n")
20
+ end
21
+
22
+ def begin_row(mode)
23
+ @td_open = '<td'
24
+ @td_close = '</td>'
25
+ row_class = ""
26
+ if (mode=="header")
27
+ @td_open = "<th"
28
+ @td_close = "</th>"
29
+ else
30
+ row_class = mode
31
+ end
32
+ tr = "<tr>"
33
+ if (row_class!="")
34
+ tr = "<tr class=\"" + row_class + "\">"
35
+ end
36
+ insert(tr)
37
+ end
38
+
39
+ def insert_cell(txt, mode)
40
+ cell_decorate = ""
41
+ if (mode!="")
42
+ cell_decorate = " class=\"" + mode + "\""
43
+ end
44
+ insert(@td_open+cell_decorate+">")
45
+ insert(txt)
46
+ insert(@td_close)
47
+ end
48
+
49
+ def end_row()
50
+ insert("</tr>\n")
51
+ end
52
+
53
+ def end_table()
54
+ insert("</table>\n")
55
+ end
56
+
57
+ def html()
58
+ return @text_to_insert.join('')
59
+ end
60
+
61
+ def to_s()
62
+ return html()
63
+ end
64
+
65
+
66
+ def self.examine_cell(x, y, value, vcol, vrow, vcorner, cell)
67
+ cell.category = ""
68
+ cell.category_given_tr = ""
69
+ cell.separator = ""
70
+ cell.conflicted = false
71
+ cell.updated = false
72
+ cell.pvalue = cell.lvalue = cell.rvalue = nil
73
+ cell.value = value
74
+ cell.value = "" if (cell.value.nil?)
75
+ cell.pretty_value = cell.value
76
+ vrow = "" if (vrow.nil?)
77
+ vcol = "" if (vcol.nil?)
78
+ removed_column = false
79
+ if (vrow == ":")
80
+ cell.category = 'move'
81
+ end
82
+ if (vcol.index("+++"))
83
+ cell.category_given_tr = cell.category = 'add'
84
+ elsif (vcol.index("---"))
85
+ cell.category_given_tr = cell.category = 'remove'
86
+ removed_column = true
87
+ end
88
+ if (vrow == "!")
89
+ cell.category = 'spec'
90
+ elsif (vrow == "@@")
91
+ cell.category = 'header'
92
+ elsif (vrow == "+++")
93
+ if (!removed_column)
94
+ cell.category = 'add'
95
+ end
96
+ elsif (vrow == "---")
97
+ cell.category = "remove"
98
+ elsif (vrow.index("->"))
99
+ if (!removed_column)
100
+ tokens = vrow.split("!")
101
+ full = vrow
102
+ part = tokens[1]
103
+ part = full if (part.nil?)
104
+ if (cell.value.index(part))
105
+ cat = "modify"
106
+ div = part
107
+ # render with utf8 -> symbol
108
+ if (part!=full)
109
+ if (cell.value.index(full))
110
+ div = full
111
+ cat = "conflict"
112
+ cell.conflicted = true
113
+ end
114
+ end
115
+ cell.updated = true
116
+ cell.separator = div
117
+ tokens = cell.pretty_value.split(div)
118
+ pretty_tokens = tokens
119
+ if (tokens.length>=2)
120
+ pretty_tokens[0] = mark_spaces(tokens[0],tokens[1])
121
+ pretty_tokens[1] = mark_spaces(tokens[1],tokens[0])
122
+ end
123
+ if (tokens.length>=3)
124
+ ref = pretty_tokens[0]
125
+ pretty_tokens[0] = mark_spaces(ref,tokens[2])
126
+ pretty_tokens[2] = mark_spaces(tokens[2],ref)
127
+ end
128
+ if (tokens.length == 0)
129
+ pretty_tokens = ['','']
130
+ end
131
+ cell.pretty_value = pretty_tokens.join("→")
132
+ cell.category_given_tr = cell.category = cat
133
+ offset = cell.conflicted ? 1 : 0
134
+ cell.lvalue = tokens[offset]
135
+ cell.rvalue = tokens[offset+1]
136
+ cell.pvalue = tokens[0] if (cell.conflicted)
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ def self.mark_spaces(sl, sr)
143
+ return sl if (sl==sr)
144
+ return sl if (sl.nil? || sr.nil?)
145
+ slc = sl.gsub(" ","")
146
+ src = sr.gsub(" ","")
147
+ return sl if (slc!=src)
148
+ slo = ""
149
+ il = 0
150
+ ir = 0
151
+ while (il<sl.length)
152
+ cl = sl[il]
153
+ cr = ""
154
+ if (ir<sr.length)
155
+ cr = sr[ir]
156
+ end
157
+ if (cl==cr)
158
+ slo += cl
159
+ il+=1
160
+ ir+=1
161
+ elsif (cr==" ")
162
+ ir+=1
163
+ else
164
+ slo += " " # this is U+2423, open box
165
+ il+=1
166
+ end
167
+ end
168
+ return slo
169
+ end
170
+
171
+ def self.render_cell(tt, x, y)
172
+ cell = Coopy::CellInfo.new
173
+ corner = tt.get_cell_text(0,0)
174
+ off = (corner=="@:@") ? 1 : 0
175
+
176
+ examine_cell(x,
177
+ y,
178
+ tt.get_cell_text(x,y),
179
+ tt.get_cell_text(x,off),
180
+ tt.get_cell_text(off,y),
181
+ corner,
182
+ cell)
183
+ return cell
184
+ end
185
+
186
+ def render(rows)
187
+ return if (rows.width==0||rows.height==0)
188
+ render = self
189
+ render.begin_table()
190
+ change_row = -1
191
+ tt = Coopy::TableText.new(rows)
192
+ cell = CellInfo.new
193
+ corner = tt.get_cell_text(0,0)
194
+ off = (corner=="@:@") ? 1 : 0
195
+ if (off>0)
196
+ return if (rows.width<=1||rows.height<=1)
197
+ end
198
+ (0...rows.height).each do |row|
199
+
200
+ @open = false
201
+
202
+ txt = tt.get_cell_text(off,row)
203
+ txt = "" if (txt.nil?)
204
+ DiffRender.examine_cell(0,row,txt,"",txt,corner,cell)
205
+ row_mode = cell.category
206
+ if (row_mode == "spec")
207
+ change_row = row
208
+ end
209
+
210
+ render.begin_row(row_mode)
211
+
212
+ (0...rows.width).each do |c|
213
+ DiffRender.examine_cell(c,
214
+ row,
215
+ tt.get_cell_text(c,row),
216
+ (change_row>=0)?tt.get_cell_text(c,change_row):"",
217
+ txt,
218
+ corner,
219
+ cell)
220
+ render.insert_cell(@pretty_arrows ? cell.pretty_value : cell.value,
221
+ cell.category_given_tr)
222
+ end
223
+ render.end_row()
224
+ end
225
+ render.end_table()
226
+ end
227
+
228
+ def sample_css()
229
+ return ".highlighter .add
230
+ background-color: #7fff7f
231
+ end
232
+
233
+ .highlighter .remove
234
+ background-color: #ff7f7f
235
+ end
236
+
237
+ .highlighter td.modify
238
+ background-color: #7f7fff
239
+ end
240
+
241
+ .highlighter td.conflict
242
+ background-color: #f00
243
+ end
244
+
245
+ .highlighter .spec
246
+ background-color: #aaa
247
+ end
248
+
249
+ .highlighter .move
250
+ background-color: #ffa
251
+ end
252
+
253
+ .highlighter .nil
254
+ color: #888
255
+ end
256
+
257
+ .highlighter table
258
+ border-collapse:collapse
259
+ end
260
+
261
+ .highlighter td, .highlighter th
262
+ border: 1px solid #2D4068
263
+ padding: 3px 7px 2px
264
+ end
265
+
266
+ .highlighter th, .highlighter .header
267
+ background-color: #aaf
268
+ font-weight: bold
269
+ padding-bottom: 4px
270
+ padding-top: 5px
271
+ text-align:left
272
+ end
273
+
274
+ .highlighter tr:first-child td
275
+ border-top: 1px solid #2D4068
276
+ end
277
+
278
+ .highlighter td:first-child
279
+ border-left: 1px solid #2D4068
280
+ end
281
+
282
+ .highlighter td
283
+ empty-cells: show
284
+ end
285
+ "
286
+ end
287
+
288
+ def completeHtml()
289
+ @text_to_insert.insert(0,"<html>
290
+ <meta charset='utf-8'>
291
+ <head>
292
+ <style TYPE='text/css'>
293
+ ")
294
+ @text_to_insert.insert(1,sample_css())
295
+ @text_to_insert.insert(2,"</style>
296
+ </head>
297
+ <body>
298
+ <div class='highlighter'>
299
+ ")
300
+ @text_to_insert.push("</div>
301
+ </body>
302
+ </html>
303
+ ")
304
+ end
305
+ end
306
+ end
307
+
@@ -0,0 +1,73 @@
1
+ module Coopy
2
+ class Index
3
+
4
+ attr_accessor :items # Hash<String,IndexItem>
5
+ attr_accessor :keys # Array<String>
6
+ attr_accessor :top_freq # integer
7
+ attr_accessor :height # integer
8
+
9
+ def initialize
10
+ @items = {}
11
+ @cols = [] # Array<integer>
12
+ @keys = []
13
+ @top_freq = 0
14
+ @height = 0
15
+ @v = nil # View
16
+ @indexed_table = nil # Table
17
+ end
18
+
19
+ def add_column(i)
20
+ @cols << i
21
+ end
22
+
23
+ def index_table(t)
24
+ @indexed_table = t
25
+ (0...t.height).each do |i|
26
+ key = ""
27
+ if @keys.length > i
28
+ key = @keys[i]
29
+ else
30
+ key = to_key(t,i)
31
+ @keys << key
32
+ end
33
+ item = @items[key]
34
+ if item.nil?
35
+ item = IndexItem.new
36
+ @items[key] = item
37
+ end
38
+ ct = item.add(i)
39
+ @top_freq = ct if ct>@top_freq
40
+ end
41
+ @height = t.height
42
+ end
43
+
44
+ def to_key(table, i)
45
+ wide = ""
46
+ @v = table.get_cell_view if @v.nil?
47
+ @cols.each_with_index do |col, k|
48
+ d = table.get_cell(col,i)
49
+ txt = @v.to_s(d)
50
+ next if (txt=="" || txt=="null" || txt=="undefined")
51
+ wide += " // " if (k>0)
52
+ wide += txt
53
+ end
54
+ wide
55
+ end
56
+
57
+ def to_key_by_content(row)
58
+ wide = ""
59
+ @cols.each_with_index do |col, k|
60
+ txt = row.get_row_string(col)
61
+ next if (txt=="" || txt=="null" || txt=="undefined")
62
+ wide += " // " if (k>0)
63
+ wide += txt
64
+ end
65
+ wide
66
+ end
67
+
68
+ def get_table
69
+ @indexed_table
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,17 @@
1
+ module Coopy
2
+ class IndexItem
3
+
4
+ attr_accessor :lst # Array<Int>
5
+
6
+ def initialize
7
+ @lst = []
8
+ end
9
+
10
+ def add(i)
11
+ @lst ||= []
12
+ @lst << i
13
+ @lst.length
14
+ end
15
+
16
+ end
17
+ end