rroonga 1.2.0 → 1.2.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.
Files changed (159) hide show
  1. data/README.textile +71 -0
  2. data/Rakefile +213 -128
  3. data/TODO +0 -0
  4. data/example/bookmark.rb +12 -12
  5. data/ext/groonga/Makefile +233 -0
  6. data/ext/groonga/extconf.rb +1 -1
  7. data/ext/groonga/rb-grn-column.c +5 -5
  8. data/ext/groonga/rb-grn-index-column.c +31 -0
  9. data/ext/groonga/rb-grn-index-cursor.c +106 -0
  10. data/ext/groonga/rb-grn-logger.c +5 -5
  11. data/ext/groonga/rb-grn-object.c +48 -0
  12. data/ext/groonga/rb-grn-patricia-trie.c +1 -1
  13. data/ext/groonga/rb-grn-plugin.c +32 -0
  14. data/ext/groonga/rb-grn-posting.c +51 -0
  15. data/ext/groonga/rb-grn-table-cursor.c +6 -1
  16. data/ext/groonga/rb-grn-table.c +31 -13
  17. data/ext/groonga/rb-grn.h +21 -3
  18. data/ext/groonga/rb-groonga.c +3 -1
  19. data/lib/groonga.rb +1 -0
  20. data/lib/groonga/dumper.rb +25 -5
  21. data/lib/groonga/expression-builder.rb +2 -2
  22. data/lib/groonga/pagination.rb +99 -7
  23. data/lib/groonga/posting.rb +87 -0
  24. data/lib/groonga/record.rb +118 -11
  25. data/lib/groonga/schema.rb +18 -1
  26. data/test/groonga-test-utils.rb +1 -6
  27. data/test/run-test.rb +13 -28
  28. data/test/test-column.rb +4 -0
  29. data/test/test-database-dumper.rb +53 -10
  30. data/test/test-hash.rb +6 -6
  31. data/test/test-index-cursor.rb +93 -0
  32. data/test/test-plugin.rb +6 -0
  33. data/test/test-record.rb +162 -1
  34. data/test/test-schema-type.rb +6 -0
  35. data/test/test-schema.rb +17 -0
  36. data/test/test-table.rb +7 -2
  37. data/test/test-type.rb +9 -1
  38. metadata +135 -245
  39. data/AUTHORS +0 -5
  40. data/NEWS.ja.rdoc +0 -344
  41. data/NEWS.rdoc +0 -346
  42. data/README.ja.rdoc +0 -68
  43. data/README.rdoc +0 -68
  44. data/example/search/config.ru +0 -230
  45. data/example/search/public/css/groonga.css +0 -122
  46. data/ext/.gitignore +0 -2
  47. data/html/bar.svg +0 -153
  48. data/html/developer.html +0 -151
  49. data/html/developer.svg +0 -469
  50. data/html/download.svg +0 -253
  51. data/html/favicon.ico +0 -0
  52. data/html/favicon.svg +0 -591
  53. data/html/footer.html.erb +0 -33
  54. data/html/head.html.erb +0 -4
  55. data/html/header.html.erb +0 -17
  56. data/html/heading-mark.svg +0 -393
  57. data/html/index.html +0 -243
  58. data/html/install.svg +0 -636
  59. data/html/logo.svg +0 -612
  60. data/html/ranguba.css +0 -342
  61. data/html/readme.svg +0 -256
  62. data/html/tutorial.svg +0 -559
  63. data/license/LGPL +0 -504
  64. data/test-unit-notify/Rakefile +0 -47
  65. data/test-unit-notify/lib/test/unit/notify.rb +0 -104
  66. data/test-unit/COPYING +0 -56
  67. data/test-unit/GPL +0 -340
  68. data/test-unit/PSFL +0 -271
  69. data/test-unit/Rakefile +0 -53
  70. data/test-unit/TODO +0 -5
  71. data/test-unit/bin/testrb +0 -5
  72. data/test-unit/html/bar.svg +0 -153
  73. data/test-unit/html/developer.svg +0 -469
  74. data/test-unit/html/favicon.ico +0 -0
  75. data/test-unit/html/favicon.svg +0 -82
  76. data/test-unit/html/heading-mark.svg +0 -393
  77. data/test-unit/html/index.html +0 -247
  78. data/test-unit/html/index.html.ja +0 -270
  79. data/test-unit/html/install.svg +0 -636
  80. data/test-unit/html/logo.svg +0 -483
  81. data/test-unit/html/test-unit.css +0 -339
  82. data/test-unit/html/tutorial.svg +0 -559
  83. data/test-unit/lib/test/unit.rb +0 -328
  84. data/test-unit/lib/test/unit/assertionfailederror.rb +0 -25
  85. data/test-unit/lib/test/unit/assertions.rb +0 -1334
  86. data/test-unit/lib/test/unit/attribute.rb +0 -125
  87. data/test-unit/lib/test/unit/autorunner.rb +0 -363
  88. data/test-unit/lib/test/unit/collector.rb +0 -36
  89. data/test-unit/lib/test/unit/collector/descendant.rb +0 -23
  90. data/test-unit/lib/test/unit/collector/dir.rb +0 -108
  91. data/test-unit/lib/test/unit/collector/load.rb +0 -144
  92. data/test-unit/lib/test/unit/collector/objectspace.rb +0 -34
  93. data/test-unit/lib/test/unit/color-scheme.rb +0 -106
  94. data/test-unit/lib/test/unit/color.rb +0 -96
  95. data/test-unit/lib/test/unit/diff.rb +0 -740
  96. data/test-unit/lib/test/unit/error.rb +0 -130
  97. data/test-unit/lib/test/unit/exceptionhandler.rb +0 -39
  98. data/test-unit/lib/test/unit/failure.rb +0 -136
  99. data/test-unit/lib/test/unit/fixture.rb +0 -176
  100. data/test-unit/lib/test/unit/notification.rb +0 -129
  101. data/test-unit/lib/test/unit/omission.rb +0 -191
  102. data/test-unit/lib/test/unit/pending.rb +0 -150
  103. data/test-unit/lib/test/unit/priority.rb +0 -180
  104. data/test-unit/lib/test/unit/runner/console.rb +0 -52
  105. data/test-unit/lib/test/unit/runner/emacs.rb +0 -8
  106. data/test-unit/lib/test/unit/runner/tap.rb +0 -8
  107. data/test-unit/lib/test/unit/testcase.rb +0 -483
  108. data/test-unit/lib/test/unit/testresult.rb +0 -121
  109. data/test-unit/lib/test/unit/testsuite.rb +0 -110
  110. data/test-unit/lib/test/unit/ui/console/outputlevel.rb +0 -14
  111. data/test-unit/lib/test/unit/ui/console/testrunner.rb +0 -430
  112. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +0 -63
  113. data/test-unit/lib/test/unit/ui/tap/testrunner.rb +0 -82
  114. data/test-unit/lib/test/unit/ui/testrunner.rb +0 -53
  115. data/test-unit/lib/test/unit/ui/testrunnermediator.rb +0 -77
  116. data/test-unit/lib/test/unit/ui/testrunnerutilities.rb +0 -41
  117. data/test-unit/lib/test/unit/util/backtracefilter.rb +0 -42
  118. data/test-unit/lib/test/unit/util/method-owner-finder.rb +0 -28
  119. data/test-unit/lib/test/unit/util/observable.rb +0 -90
  120. data/test-unit/lib/test/unit/util/output.rb +0 -31
  121. data/test-unit/lib/test/unit/util/procwrapper.rb +0 -48
  122. data/test-unit/lib/test/unit/version.rb +0 -7
  123. data/test-unit/sample/adder.rb +0 -13
  124. data/test-unit/sample/subtracter.rb +0 -12
  125. data/test-unit/sample/test_adder.rb +0 -20
  126. data/test-unit/sample/test_subtracter.rb +0 -20
  127. data/test-unit/sample/test_user.rb +0 -23
  128. data/test-unit/test/collector/test-descendant.rb +0 -133
  129. data/test-unit/test/collector/test-load.rb +0 -442
  130. data/test-unit/test/collector/test_dir.rb +0 -406
  131. data/test-unit/test/collector/test_objectspace.rb +0 -100
  132. data/test-unit/test/run-test.rb +0 -15
  133. data/test-unit/test/test-attribute.rb +0 -86
  134. data/test-unit/test/test-color-scheme.rb +0 -69
  135. data/test-unit/test/test-color.rb +0 -47
  136. data/test-unit/test/test-diff.rb +0 -518
  137. data/test-unit/test/test-emacs-runner.rb +0 -60
  138. data/test-unit/test/test-fixture.rb +0 -287
  139. data/test-unit/test/test-notification.rb +0 -33
  140. data/test-unit/test/test-omission.rb +0 -81
  141. data/test-unit/test/test-pending.rb +0 -70
  142. data/test-unit/test/test-priority.rb +0 -119
  143. data/test-unit/test/test-testcase.rb +0 -544
  144. data/test-unit/test/test_assertions.rb +0 -1197
  145. data/test-unit/test/test_error.rb +0 -26
  146. data/test-unit/test/test_failure.rb +0 -33
  147. data/test-unit/test/test_testresult.rb +0 -113
  148. data/test-unit/test/test_testsuite.rb +0 -129
  149. data/test-unit/test/testunit-test-util.rb +0 -14
  150. data/test-unit/test/ui/test_tap.rb +0 -33
  151. data/test-unit/test/ui/test_testrunmediator.rb +0 -20
  152. data/test-unit/test/util/test-method-owner-finder.rb +0 -38
  153. data/test-unit/test/util/test-output.rb +0 -11
  154. data/test-unit/test/util/test_backtracefilter.rb +0 -41
  155. data/test-unit/test/util/test_observable.rb +0 -102
  156. data/test-unit/test/util/test_procwrapper.rb +0 -36
  157. data/test/.gitignore +0 -1
  158. data/text/expression.rdoc +0 -285
  159. data/text/tutorial.ja.rdoc +0 -433
@@ -1,96 +0,0 @@
1
- module Test
2
- module Unit
3
- class Color
4
- NAMES = ["black", "red", "green", "yellow",
5
- "blue", "magenta", "cyan", "white"]
6
-
7
- attr_reader :name
8
- def initialize(name, options={})
9
- @name = name
10
- @foreground = options[:foreground]
11
- @foreground = true if @foreground.nil?
12
- @intensity = options[:intensity]
13
- @bold = options[:bold]
14
- @italic = options[:italic]
15
- @underline = options[:underline]
16
- end
17
-
18
- def foreground?
19
- @foreground
20
- end
21
-
22
- def intensity?
23
- @intensity
24
- end
25
-
26
- def bold?
27
- @bold
28
- end
29
-
30
- def italic?
31
- @italic
32
- end
33
-
34
- def underline?
35
- @underline
36
- end
37
-
38
- def ==(other)
39
- self.class === other and
40
- [name, foreground?, intensity?,
41
- bold?, italic?, underline?] ==
42
- [other.name, other.foreground?, other.intensity?,
43
- other.bold?, other.italic?, other.underline?]
44
- end
45
-
46
- def sequence
47
- sequence = []
48
- if @name == "none"
49
- elsif @name == "reset"
50
- sequence << "0"
51
- else
52
- foreground_parameter = foreground? ? 3 : 4
53
- foreground_parameter += 6 if intensity?
54
- sequence << "#{foreground_parameter}#{NAMES.index(@name)}"
55
- end
56
- sequence << "1" if bold?
57
- sequence << "3" if italic?
58
- sequence << "4" if underline?
59
- sequence
60
- end
61
-
62
- def escape_sequence
63
- "\e[#{sequence.join(';')}m"
64
- end
65
-
66
- def +(other)
67
- MixColor.new([self, other])
68
- end
69
- end
70
-
71
- class MixColor
72
- attr_reader :colors
73
- def initialize(colors)
74
- @colors = colors
75
- end
76
-
77
- def sequence
78
- @colors.inject([]) do |result, color|
79
- result + color.sequence
80
- end
81
- end
82
-
83
- def escape_sequence
84
- "\e[#{sequence.join(';')}m"
85
- end
86
-
87
- def +(other)
88
- self.class.new([self, other])
89
- end
90
-
91
- def ==(other)
92
- self.class === other and colors == other.colors
93
- end
94
- end
95
- end
96
- end
@@ -1,740 +0,0 @@
1
- # port of Python's difflib.
2
- #
3
- # Copyright (c) 2001-2008 Python Software Foundation; All Rights Reserved
4
- # Copyright (c) 2008-2010 Kouhei Sutou; All Rights Reserved
5
- #
6
- # It is free software, and is distributed under the Ruby
7
- # license and/or the PSF license. See the COPYING file and
8
- # PSFL file.
9
-
10
- module Test
11
- module Unit
12
- module Diff
13
- class SequenceMatcher
14
- def initialize(from, to, &junk_predicate)
15
- @from = from
16
- @to = to
17
- @junk_predicate = junk_predicate
18
- update_to_indexes
19
- end
20
-
21
- def longest_match(from_start, from_end, to_start, to_end)
22
- best_info = find_best_match_position(from_start, from_end,
23
- to_start, to_end)
24
- unless @junks.empty?
25
- args = [from_start, from_end, to_start, to_end]
26
- best_info = adjust_best_info_with_junk_predicate(false, best_info,
27
- *args)
28
- best_info = adjust_best_info_with_junk_predicate(true, best_info,
29
- *args)
30
- end
31
-
32
- best_info
33
- end
34
-
35
- def blocks
36
- @blocks ||= compute_blocks
37
- end
38
-
39
- def operations
40
- @operations ||= compute_operations
41
- end
42
-
43
- def grouped_operations(context_size=nil)
44
- context_size ||= 3
45
- _operations = operations.dup
46
- _operations = [[:equal, 0, 0, 0, 0]] if _operations.empty?
47
- expand_edge_equal_operations!(_operations, context_size)
48
-
49
- group_window = context_size * 2
50
- groups = []
51
- group = []
52
- _operations.each do |tag, from_start, from_end, to_start, to_end|
53
- if tag == :equal and from_end - from_start > group_window
54
- group << [tag,
55
- from_start,
56
- [from_end, from_start + context_size].min,
57
- to_start,
58
- [to_end, to_start + context_size].min]
59
- groups << group
60
- group = []
61
- from_start = [from_start, from_end - context_size].max
62
- to_start = [to_start, to_end - context_size].max
63
- end
64
- group << [tag, from_start, from_end, to_start, to_end]
65
- end
66
- groups << group unless group.empty?
67
- groups
68
- end
69
-
70
- def ratio
71
- @ratio ||= compute_ratio
72
- end
73
-
74
- private
75
- def update_to_indexes
76
- @to_indexes = {}
77
- @junks = {}
78
- if @to.is_a?(String)
79
- each = " "[0].is_a?(Integer) ? :each_byte : :each_char
80
- else
81
- each = :each
82
- end
83
- i = 0
84
- @to.send(each) do |item|
85
- @to_indexes[item] ||= []
86
- @to_indexes[item] << i
87
- i += 1
88
- end
89
-
90
- return if @junk_predicate.nil?
91
- @to_indexes = @to_indexes.reject do |key, value|
92
- junk = @junk_predicate.call(key)
93
- @junks[key] = true if junk
94
- junk
95
- end
96
- end
97
-
98
- def find_best_match_position(from_start, from_end, to_start, to_end)
99
- best_from, best_to, best_size = from_start, to_start, 0
100
- sizes = {}
101
- from_start.upto(from_end) do |from_index|
102
- _sizes = {}
103
- (@to_indexes[@from[from_index]] || []).each do |to_index|
104
- next if to_index < to_start
105
- break if to_index > to_end
106
- size = _sizes[to_index] = (sizes[to_index - 1] || 0) + 1
107
- if size > best_size
108
- best_from = from_index - size + 1
109
- best_to = to_index - size + 1
110
- best_size = size
111
- end
112
- end
113
- sizes = _sizes
114
- end
115
- [best_from, best_to, best_size]
116
- end
117
-
118
- def adjust_best_info_with_junk_predicate(should_junk, best_info,
119
- from_start, from_end,
120
- to_start, to_end)
121
- best_from, best_to, best_size = best_info
122
- while best_from > from_start and best_to > to_start and
123
- (should_junk ?
124
- @junks.has_key?(@to[best_to - 1]) :
125
- !@junks.has_key?(@to[best_to - 1])) and
126
- @from[best_from - 1] == @to[best_to - 1]
127
- best_from -= 1
128
- best_to -= 1
129
- best_size += 1
130
- end
131
-
132
- while best_from + best_size < from_end and
133
- best_to + best_size < to_end and
134
- (should_junk ?
135
- @junks.has_key?(@to[best_to + best_size]) :
136
- !@junks.has_key?(@to[best_to + best_size])) and
137
- @from[best_from + best_size] == @to[best_to + best_size]
138
- best_size += 1
139
- end
140
-
141
- [best_from, best_to, best_size]
142
- end
143
-
144
- def matches
145
- @matches ||= compute_matches
146
- end
147
-
148
- def compute_matches
149
- matches = []
150
- queue = [[0, @from.size, 0, @to.size]]
151
- until queue.empty?
152
- from_start, from_end, to_start, to_end = queue.pop
153
- match = longest_match(from_start, from_end - 1, to_start, to_end - 1)
154
- match_from_index, match_to_index, size = match
155
- unless size.zero?
156
- if from_start < match_from_index and
157
- to_start < match_to_index
158
- queue.push([from_start, match_from_index,
159
- to_start, match_to_index])
160
- end
161
- matches << match
162
- if match_from_index + size < from_end and
163
- match_to_index + size < to_end
164
- queue.push([match_from_index + size, from_end,
165
- match_to_index + size, to_end])
166
- end
167
- end
168
- end
169
- matches.sort_by do |(from_index, to_index, match_size)|
170
- from_index
171
- end
172
- end
173
-
174
- def compute_blocks
175
- blocks = []
176
- current_from_index = current_to_index = current_size = 0
177
- matches.each do |from_index, to_index, size|
178
- if current_from_index + current_size == from_index and
179
- current_to_index + current_size == to_index
180
- current_size += size
181
- else
182
- unless current_size.zero?
183
- blocks << [current_from_index, current_to_index, current_size]
184
- end
185
- current_from_index = from_index
186
- current_to_index = to_index
187
- current_size = size
188
- end
189
- end
190
- unless current_size.zero?
191
- blocks << [current_from_index, current_to_index, current_size]
192
- end
193
-
194
- blocks << [@from.size, @to.size, 0]
195
- blocks
196
- end
197
-
198
- def compute_operations
199
- from_index = to_index = 0
200
- operations = []
201
- blocks.each do |match_from_index, match_to_index, size|
202
- tag = determine_tag(from_index, to_index,
203
- match_from_index, match_to_index)
204
- if tag != :equal
205
- operations << [tag,
206
- from_index, match_from_index,
207
- to_index, match_to_index]
208
- end
209
-
210
- from_index, to_index = match_from_index + size, match_to_index + size
211
- if size > 0
212
- operations << [:equal,
213
- match_from_index, from_index,
214
- match_to_index, to_index]
215
- end
216
- end
217
- operations
218
- end
219
-
220
- def compute_ratio
221
- matches = blocks.inject(0) {|result, block| result + block[-1]}
222
- length = @from.length + @to.length
223
- if length.zero?
224
- 1.0
225
- else
226
- 2.0 * matches / length
227
- end
228
- end
229
-
230
- def determine_tag(from_index, to_index,
231
- match_from_index, match_to_index)
232
- if from_index < match_from_index and to_index < match_to_index
233
- :replace
234
- elsif from_index < match_from_index
235
- :delete
236
- elsif to_index < match_to_index
237
- :insert
238
- else
239
- :equal
240
- end
241
- end
242
-
243
- def expand_edge_equal_operations!(_operations, context_size)
244
- tag, from_start, from_end, to_start, to_end = _operations[0]
245
- if tag == :equal
246
- _operations[0] = [tag,
247
- [from_start, from_end - context_size].max,
248
- from_end,
249
- [to_start, to_end - context_size].max,
250
- to_end]
251
- end
252
-
253
- tag, from_start, from_end, to_start, to_end = _operations[-1]
254
- if tag == :equal
255
- _operations[-1] = [tag,
256
- from_start,
257
- [from_end, from_start + context_size].min,
258
- to_start,
259
- [to_end, to_start + context_size].min]
260
- end
261
- end
262
- end
263
-
264
- class Differ
265
- def initialize(from, to)
266
- @from = from
267
- @to = to
268
- end
269
-
270
- private
271
- def tag(mark, contents)
272
- contents.collect {|content| "#{mark}#{content}"}
273
- end
274
- end
275
-
276
- class UTF8Line
277
- class << self
278
- # from http://unicode.org/reports/tr11/
279
- WIDE_CHARACTERS =
280
- [0x1100..0x1159, 0x115F..0x115F, 0x2329..0x232A,
281
- 0x2E80..0x2E99, 0x2E9B..0x2EF3, 0x2F00..0x2FD5,
282
- 0x2FF0..0x2FFB, 0x3000..0x303E, 0x3041..0x3096,
283
- 0x3099..0x30FF, 0x3105..0x312D, 0x3131..0x318E,
284
- 0x3190..0x31B7, 0x31C0..0x31E3, 0x31F0..0x321E,
285
- 0x3220..0x3243, 0x3250..0x32FE, 0x3300..0x4DB5,
286
- 0x4E00..0x9FC3, 0xA000..0xA48C, 0xA490..0xA4C6,
287
- 0xAC00..0xD7A3, 0xF900..0xFA2D, 0xFA30..0xFA6A,
288
- 0xFA70..0xFAD9, 0xFE10..0xFE19, 0xFE30..0xFE52,
289
- 0xFE54..0xFE66, 0xFE68..0xFE6B, 0xFF01..0xFF60,
290
- 0xFFE0..0xFFE6, 0x20000..0x2FFFD, 0x30000..0x3FFFD,
291
- ]
292
-
293
- AMBIGUOUS =
294
- [0x00A1..0x00A1, 0x00A4..0x00A4, 0x00A7..0x00A8,
295
- 0x00AA..0x00AA, 0x00AD..0x00AE, 0x00B0..0x00B4,
296
- 0x00B6..0x00BA, 0x00BC..0x00BF, 0x00C6..0x00C6,
297
- 0x00D0..0x00D0, 0x00D7..0x00D8, 0x00DE..0x00E1,
298
- 0x00E6..0x00E6, 0x00E8..0x00EA, 0x00EC..0x00ED,
299
- 0x00F0..0x00F0, 0x00F2..0x00F3, 0x00F7..0x00FA,
300
- 0x00FC..0x00FC, 0x00FE..0x00FE, 0x0101..0x0101,
301
- 0x0111..0x0111, 0x0113..0x0113, 0x011B..0x011B,
302
- 0x0126..0x0127, 0x012B..0x012B, 0x0131..0x0133,
303
- 0x0138..0x0138, 0x013F..0x0142, 0x0144..0x0144,
304
- 0x0148..0x014B, 0x014D..0x014D, 0x0152..0x0153,
305
- 0x0166..0x0167, 0x016B..0x016B, 0x01CE..0x01CE,
306
- 0x01D0..0x01D0, 0x01D2..0x01D2, 0x01D4..0x01D4,
307
- 0x01D6..0x01D6, 0x01D8..0x01D8, 0x01DA..0x01DA,
308
- 0x01DC..0x01DC, 0x0251..0x0251, 0x0261..0x0261,
309
- 0x02C4..0x02C4, 0x02C7..0x02C7, 0x02C9..0x02CB,
310
- 0x02CD..0x02CD, 0x02D0..0x02D0, 0x02D8..0x02DB,
311
- 0x02DD..0x02DD, 0x02DF..0x02DF, 0x0300..0x036F,
312
- 0x0391..0x03A1, 0x03A3..0x03A9, 0x03B1..0x03C1,
313
- 0x03C3..0x03C9, 0x0401..0x0401, 0x0410..0x044F,
314
- 0x0451..0x0451, 0x2010..0x2010, 0x2013..0x2016,
315
- 0x2018..0x2019, 0x201C..0x201D, 0x2020..0x2022,
316
- 0x2024..0x2027, 0x2030..0x2030, 0x2032..0x2033,
317
- 0x2035..0x2035, 0x203B..0x203B, 0x203E..0x203E,
318
- 0x2074..0x2074, 0x207F..0x207F, 0x2081..0x2084,
319
- 0x20AC..0x20AC, 0x2103..0x2103, 0x2105..0x2105,
320
- 0x2109..0x2109, 0x2113..0x2113, 0x2116..0x2116,
321
- 0x2121..0x2122, 0x2126..0x2126, 0x212B..0x212B,
322
- 0x2153..0x2154, 0x215B..0x215E, 0x2160..0x216B,
323
- 0x2170..0x2179, 0x2190..0x2199, 0x21B8..0x21B9,
324
- 0x21D2..0x21D2, 0x21D4..0x21D4, 0x21E7..0x21E7,
325
- 0x2200..0x2200, 0x2202..0x2203, 0x2207..0x2208,
326
- 0x220B..0x220B, 0x220F..0x220F, 0x2211..0x2211,
327
- 0x2215..0x2215, 0x221A..0x221A, 0x221D..0x2220,
328
- 0x2223..0x2223, 0x2225..0x2225, 0x2227..0x222C,
329
- 0x222E..0x222E, 0x2234..0x2237, 0x223C..0x223D,
330
- 0x2248..0x2248, 0x224C..0x224C, 0x2252..0x2252,
331
- 0x2260..0x2261, 0x2264..0x2267, 0x226A..0x226B,
332
- 0x226E..0x226F, 0x2282..0x2283, 0x2286..0x2287,
333
- 0x2295..0x2295, 0x2299..0x2299, 0x22A5..0x22A5,
334
- 0x22BF..0x22BF, 0x2312..0x2312, 0x2460..0x24E9,
335
- 0x24EB..0x254B, 0x2550..0x2573, 0x2580..0x258F,
336
- 0x2592..0x2595, 0x25A0..0x25A1, 0x25A3..0x25A9,
337
- 0x25B2..0x25B3, 0x25B6..0x25B7, 0x25BC..0x25BD,
338
- 0x25C0..0x25C1, 0x25C6..0x25C8, 0x25CB..0x25CB,
339
- 0x25CE..0x25D1, 0x25E2..0x25E5, 0x25EF..0x25EF,
340
- 0x2605..0x2606, 0x2609..0x2609, 0x260E..0x260F,
341
- 0x2614..0x2615, 0x261C..0x261C, 0x261E..0x261E,
342
- 0x2640..0x2640, 0x2642..0x2642, 0x2660..0x2661,
343
- 0x2663..0x2665, 0x2667..0x266A, 0x266C..0x266D,
344
- 0x266F..0x266F, 0x273D..0x273D, 0x2776..0x277F,
345
- 0xE000..0xF8FF, 0xFE00..0xFE0F, 0xFFFD..0xFFFD,
346
- 0xE0100..0xE01EF, 0xF0000..0xFFFFD, 0x100000..0x10FFFD,
347
- ]
348
-
349
- def wide_character?(character)
350
- binary_search_ranges(character, WIDE_CHARACTERS) or
351
- binary_search_ranges(character, AMBIGUOUS)
352
- end
353
-
354
- private
355
- def binary_search_ranges(character, ranges)
356
- if ranges.size.zero?
357
- false
358
- elsif ranges.size == 1
359
- ranges[0].include?(character)
360
- else
361
- half = ranges.size / 2
362
- range = ranges[half]
363
- if range.include?(character)
364
- true
365
- elsif character < range.begin
366
- binary_search_ranges(character, ranges[0...half])
367
- else
368
- binary_search_ranges(character, ranges[(half + 1)..-1])
369
- end
370
- end
371
- end
372
- end
373
-
374
- def initialize(line)
375
- @line = line
376
- @characters = @line.unpack("U*")
377
- end
378
-
379
- def [](*args)
380
- result = @characters[*args]
381
- if result.respond_to?(:pack)
382
- result.pack("U*")
383
- else
384
- result
385
- end
386
- end
387
-
388
- def each(&block)
389
- @characters.each(&block)
390
- end
391
-
392
- def size
393
- @characters.size
394
- end
395
-
396
- def to_s
397
- @line
398
- end
399
-
400
- def compute_width(start, _end)
401
- width = 0
402
- start.upto(_end - 1) do |i|
403
- if self.class.wide_character?(@characters[i])
404
- width += 2
405
- else
406
- width += 1
407
- end
408
- end
409
- width
410
- end
411
- end
412
-
413
- class ReadableDiffer < Differ
414
- def diff(options={})
415
- @result = []
416
- operations.each do |tag, from_start, from_end, to_start, to_end|
417
- case tag
418
- when :replace
419
- diff_lines(from_start, from_end, to_start, to_end)
420
- when :delete
421
- tag_deleted(@from[from_start...from_end])
422
- when :insert
423
- tag_inserted(@to[to_start...to_end])
424
- when :equal
425
- tag_equal(@from[from_start...from_end])
426
- else
427
- raise "unknown tag: #{tag}"
428
- end
429
- end
430
- @result
431
- end
432
-
433
- private
434
- def operations
435
- @operations ||= nil
436
- if @operations.nil?
437
- matcher = SequenceMatcher.new(@from, @to)
438
- @operations = matcher.operations
439
- end
440
- @operations
441
- end
442
-
443
- def default_ratio
444
- 0.74
445
- end
446
-
447
- def cut_off_ratio
448
- 0.75
449
- end
450
-
451
- def tag(mark, contents)
452
- contents.each do |content|
453
- @result << "#{mark}#{content}"
454
- end
455
- end
456
-
457
- def tag_deleted(contents)
458
- tag("- ", contents)
459
- end
460
-
461
- def tag_inserted(contents)
462
- tag("+ ", contents)
463
- end
464
-
465
- def tag_equal(contents)
466
- tag(" ", contents)
467
- end
468
-
469
- def tag_difference(contents)
470
- tag("? ", contents)
471
- end
472
-
473
- def find_diff_line_info(from_start, from_end, to_start, to_end)
474
- best_ratio = default_ratio
475
- from_equal_index = to_equal_index = nil
476
- from_best_index = to_best_index = nil
477
-
478
- to_start.upto(to_end - 1) do |to_index|
479
- from_start.upto(from_end - 1) do |from_index|
480
- if @from[from_index] == @to[to_index]
481
- from_equal_index ||= from_index
482
- to_equal_index ||= to_index
483
- next
484
- end
485
-
486
- matcher = SequenceMatcher.new(@from[from_index], @to[to_index],
487
- &method(:space_character?))
488
- if matcher.ratio > best_ratio
489
- best_ratio = matcher.ratio
490
- from_best_index = from_index
491
- to_best_index = to_index
492
- end
493
- end
494
- end
495
-
496
- [best_ratio,
497
- from_equal_index, to_equal_index,
498
- from_best_index, to_best_index]
499
- end
500
-
501
- def diff_lines(from_start, from_end, to_start, to_end)
502
- info = find_diff_line_info(from_start, from_end, to_start, to_end)
503
- best_ratio, from_equal_index, to_equal_index, *info = info
504
- from_best_index, to_best_index = info
505
- from_best_index ||= from_start
506
- to_best_index ||= to_start
507
-
508
- if best_ratio < cut_off_ratio
509
- if from_equal_index.nil?
510
- if to_end - to_start < from_end - from_start
511
- tag_inserted(@to[to_start...to_end])
512
- tag_deleted(@from[from_start...from_end])
513
- else
514
- tag_deleted(@from[from_start...from_end])
515
- tag_inserted(@to[to_start...to_end])
516
- end
517
- return
518
- end
519
- from_best_index = from_equal_index
520
- to_best_index = to_equal_index
521
- best_ratio = 1.0
522
- end
523
-
524
- _diff_lines(from_start, from_best_index, to_start, to_best_index)
525
- diff_line(@from[from_best_index], @to[to_best_index])
526
- _diff_lines(from_best_index + 1, from_end, to_best_index + 1, to_end)
527
- end
528
-
529
- def _diff_lines(from_start, from_end, to_start, to_end)
530
- if from_start < from_end
531
- if to_start < to_end
532
- diff_lines(from_start, from_end, to_start, to_end)
533
- else
534
- tag_deleted(@from[from_start...from_end])
535
- end
536
- else
537
- tag_inserted(@to[to_start...to_end])
538
- end
539
- end
540
-
541
- def line_operations(from_line, to_line)
542
- if !from_line.respond_to?(:force_encoding) and $KCODE == "UTF8"
543
- from_line = UTF8Line.new(from_line)
544
- to_line = UTF8Line.new(to_line)
545
- end
546
- matcher = SequenceMatcher.new(from_line, to_line,
547
- &method(:space_character?))
548
- [from_line, to_line, matcher.operations]
549
- end
550
-
551
- def compute_width(line, start, _end)
552
- if line.respond_to?(:encoding) and
553
- Encoding.compatible?(Encoding::UTF_8, line.encoding)
554
- utf8_line = line[start..._end].encode(Encoding::UTF_8)
555
- width = 0
556
- utf8_line.each_codepoint do |unicode_codepoint|
557
- if UTF8Line.wide_character?(unicode_codepoint)
558
- width += 2
559
- else
560
- width += 1
561
- end
562
- end
563
- width
564
- elsif line.is_a?(UTF8Line)
565
- line.compute_width(start, _end)
566
- else
567
- _end - start
568
- end
569
- end
570
-
571
- def diff_line(from_line, to_line)
572
- from_tags = ""
573
- to_tags = ""
574
- from_line, to_line, _operations = line_operations(from_line, to_line)
575
- _operations.each do |tag, from_start, from_end, to_start, to_end|
576
- from_width = compute_width(from_line, from_start, from_end)
577
- to_width = compute_width(to_line, to_start, to_end)
578
- case tag
579
- when :replace
580
- from_tags << "^" * from_width
581
- to_tags << "^" * to_width
582
- when :delete
583
- from_tags << "-" * from_width
584
- when :insert
585
- to_tags << "+" * to_width
586
- when :equal
587
- from_tags << " " * from_width
588
- to_tags << " " * to_width
589
- else
590
- raise "unknown tag: #{tag}"
591
- end
592
- end
593
- format_diff_point(from_line, to_line, from_tags, to_tags)
594
- end
595
-
596
- def format_diff_point(from_line, to_line, from_tags, to_tags)
597
- common = [n_leading_characters(from_line, ?\t),
598
- n_leading_characters(to_line, ?\t)].min
599
- common = [common,
600
- n_leading_characters(from_tags[0, common], " "[0])].min
601
- from_tags = from_tags[common..-1].rstrip
602
- to_tags = to_tags[common..-1].rstrip
603
-
604
- result = tag_deleted([from_line])
605
- unless from_tags.empty?
606
- tag_difference(["#{"\t" * common}#{from_tags}"])
607
- end
608
- tag_inserted([to_line])
609
- unless to_tags.empty?
610
- tag_difference(["#{"\t" * common}#{to_tags}"])
611
- end
612
- end
613
-
614
- def n_leading_characters(string, character)
615
- n = 0
616
- while string[n] == character
617
- n += 1
618
- end
619
- n
620
- end
621
-
622
- def space_character?(character)
623
- [" "[0], "\t"[0]].include?(character)
624
- end
625
- end
626
-
627
- class UnifiedDiffer < Differ
628
- def diff(options={})
629
- groups = SequenceMatcher.new(@from, @to).grouped_operations
630
- return [] if groups.empty?
631
- return [] if same_content?(groups)
632
-
633
- show_context = options[:show_context]
634
- show_context = true if show_context.nil?
635
- result = ["--- #{options[:from_label]}".rstrip,
636
- "+++ #{options[:to_label]}".rstrip]
637
- groups.each do |operations|
638
- result << format_summary(operations, show_context)
639
- operations.each do |args|
640
- operation_tag, from_start, from_end, to_start, to_end = args
641
- case operation_tag
642
- when :replace
643
- result.concat(tag("-", @from[from_start...from_end]))
644
- result.concat(tag("+", @to[to_start...to_end]))
645
- when :delete
646
- result.concat(tag("-", @from[from_start...from_end]))
647
- when :insert
648
- result.concat(tag("+", @to[to_start...to_end]))
649
- when :equal
650
- result.concat(tag(" ", @from[from_start...from_end]))
651
- end
652
- end
653
- end
654
- result
655
- end
656
-
657
- private
658
- def same_content?(groups)
659
- return false if groups.size != 1
660
- group = groups[0]
661
- return false if group.size != 1
662
- tag, from_start, from_end, to_start, to_end = group[0]
663
-
664
- tag == :equal and [from_start, from_end] == [to_start, to_end]
665
- end
666
-
667
- def format_summary(operations, show_context)
668
- _, first_from_start, _, first_to_start, _ = operations[0]
669
- _, _, last_from_end, _, last_to_end = operations[-1]
670
- summary = "@@ -%d,%d +%d,%d @@" % [first_from_start + 1,
671
- last_from_end - first_from_start,
672
- first_to_start + 1,
673
- last_to_end - first_to_start,]
674
- if show_context
675
- interesting_line = find_interesting_line(first_from_start,
676
- first_to_start,
677
- :define_line?)
678
- summary << " #{interesting_line}" if interesting_line
679
- end
680
- summary
681
- end
682
-
683
- def find_interesting_line(from_start, to_start, predicate)
684
- from_index = from_start
685
- to_index = to_start
686
- while from_index >= 0 or to_index >= 0
687
- [@from[from_index], @to[to_index]].each do |line|
688
- return line if line and send(predicate, line)
689
- end
690
-
691
- from_index -= 1
692
- to_index -= 1
693
- end
694
- nil
695
- end
696
-
697
- def define_line?(line)
698
- /\A(?:[_a-zA-Z$]|\s*(?:class|module|def)\b)/ =~ line
699
- end
700
- end
701
-
702
- module_function
703
- def need_fold?(diff)
704
- /^[-+].{79}/ =~ diff
705
- end
706
-
707
- def fold(string)
708
- string.split(/\r?\n/).collect do |line|
709
- line.gsub(/(.{78})/, "\\1\n")
710
- end.join("\n")
711
- end
712
-
713
- def folded_readable(from, to, options={})
714
- readable(fold(from), fold(to), options)
715
- end
716
-
717
- def readable(from, to, options={})
718
- diff(ReadableDiffer, from, to, options)
719
- end
720
-
721
- def unified(from, to, options={})
722
- diff(UnifiedDiffer, from, to, options)
723
- end
724
-
725
- def diff(differ_class, from, to, options={})
726
- differ = differ_class.new(from.split(/\r?\n/), to.split(/\r?\n/))
727
- lines = differ.diff(options)
728
- if Object.const_defined?(:EncodingError)
729
- begin
730
- lines.join("\n")
731
- rescue EncodingError
732
- lines.collect {|line| line.force_encoding("ASCII-8BIT")}.join("\n")
733
- end
734
- else
735
- lines.join("\n")
736
- end
737
- end
738
- end
739
- end
740
- end