slimkeyfy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +22 -0
  6. data/LICENSE +21 -0
  7. data/README.md +172 -0
  8. data/bin/slimkeyfy +5 -0
  9. data/lib/.DS_Store +0 -0
  10. data/lib/slimkeyfy/console/command_line.rb +90 -0
  11. data/lib/slimkeyfy/console/io_action.rb +30 -0
  12. data/lib/slimkeyfy/console/printer.rb +50 -0
  13. data/lib/slimkeyfy/console/translate.rb +101 -0
  14. data/lib/slimkeyfy/console.rb +8 -0
  15. data/lib/slimkeyfy/slimutils/file_utils.rb +61 -0
  16. data/lib/slimkeyfy/slimutils/hash_merging.rb +84 -0
  17. data/lib/slimkeyfy/slimutils/key_generator.rb +70 -0
  18. data/lib/slimkeyfy/slimutils/yaml_processor.rb +56 -0
  19. data/lib/slimkeyfy/slimutils.rb +8 -0
  20. data/lib/slimkeyfy/transformer/base_transformer.rb +42 -0
  21. data/lib/slimkeyfy/transformer/controller_transformer.rb +20 -0
  22. data/lib/slimkeyfy/transformer/slim_transformer.rb +92 -0
  23. data/lib/slimkeyfy/transformer/whitespacer.rb +48 -0
  24. data/lib/slimkeyfy/transformer/word.rb +49 -0
  25. data/lib/slimkeyfy/transformer.rb +9 -0
  26. data/lib/slimkeyfy/version.rb +3 -0
  27. data/lib/slimkeyfy.rb +12 -0
  28. data/slimkeyfy.gemspec +21 -0
  29. data/vendor/bundle/bin/htmldiff +25 -0
  30. data/vendor/bundle/bin/ldiff +25 -0
  31. data/vendor/bundle/bin/rspec +23 -0
  32. data/vendor/bundle/build_info/diff-lcs-1.2.5.info +1 -0
  33. data/vendor/bundle/build_info/rspec-3.0.0.info +1 -0
  34. data/vendor/bundle/build_info/rspec-core-3.0.2.info +1 -0
  35. data/vendor/bundle/build_info/rspec-expectations-3.0.2.info +1 -0
  36. data/vendor/bundle/build_info/rspec-mocks-3.0.2.info +1 -0
  37. data/vendor/bundle/build_info/rspec-support-3.0.2.info +1 -0
  38. data/vendor/bundle/gems/diff-lcs-1.2.5/.autotest +3 -0
  39. data/vendor/bundle/gems/diff-lcs-1.2.5/.gemtest +0 -0
  40. data/vendor/bundle/gems/diff-lcs-1.2.5/.hoerc +2 -0
  41. data/vendor/bundle/gems/diff-lcs-1.2.5/.rspec +2 -0
  42. data/vendor/bundle/gems/diff-lcs-1.2.5/.travis.yml +22 -0
  43. data/vendor/bundle/gems/diff-lcs-1.2.5/Contributing.rdoc +64 -0
  44. data/vendor/bundle/gems/diff-lcs-1.2.5/Gemfile +20 -0
  45. data/vendor/bundle/gems/diff-lcs-1.2.5/History.rdoc +152 -0
  46. data/vendor/bundle/gems/diff-lcs-1.2.5/License.rdoc +39 -0
  47. data/vendor/bundle/gems/diff-lcs-1.2.5/Manifest.txt +38 -0
  48. data/vendor/bundle/gems/diff-lcs-1.2.5/README.rdoc +85 -0
  49. data/vendor/bundle/gems/diff-lcs-1.2.5/Rakefile +41 -0
  50. data/vendor/bundle/gems/diff-lcs-1.2.5/autotest/discover.rb +1 -0
  51. data/vendor/bundle/gems/diff-lcs-1.2.5/bin/htmldiff +32 -0
  52. data/vendor/bundle/gems/diff-lcs-1.2.5/bin/ldiff +6 -0
  53. data/vendor/bundle/gems/diff-lcs-1.2.5/docs/COPYING.txt +339 -0
  54. data/vendor/bundle/gems/diff-lcs-1.2.5/docs/artistic.txt +127 -0
  55. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/array.rb +7 -0
  56. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/block.rb +37 -0
  57. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/callbacks.rb +322 -0
  58. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/change.rb +177 -0
  59. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/htmldiff.rb +149 -0
  60. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/hunk.rb +276 -0
  61. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/internals.rb +301 -0
  62. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/ldiff.rb +195 -0
  63. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs/string.rb +5 -0
  64. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff/lcs.rb +805 -0
  65. data/vendor/bundle/gems/diff-lcs-1.2.5/lib/diff-lcs.rb +3 -0
  66. data/vendor/bundle/gems/rspec-3.0.0/License.txt +24 -0
  67. data/vendor/bundle/gems/rspec-3.0.0/README.md +47 -0
  68. data/vendor/bundle/gems/rspec-3.0.0/lib/rspec.rb +3 -0
  69. data/vendor/bundle/gems/rspec-core-3.0.2/.document +5 -0
  70. data/vendor/bundle/gems/rspec-core-3.0.2/.yardopts +7 -0
  71. data/vendor/bundle/gems/rspec-core-3.0.2/Changelog.md +1466 -0
  72. data/vendor/bundle/gems/rspec-core-3.0.2/License.txt +25 -0
  73. data/vendor/bundle/gems/rspec-core-3.0.2/README.md +243 -0
  74. data/vendor/bundle/gems/rspec-core-3.0.2/exe/rspec +4 -0
  75. data/vendor/bundle/gems/rspec-expectations-3.0.2/.document +5 -0
  76. data/vendor/bundle/gems/rspec-expectations-3.0.2/.yardopts +6 -0
  77. data/vendor/bundle/gems/rspec-expectations-3.0.2/Changelog.md +749 -0
  78. data/vendor/bundle/gems/rspec-expectations-3.0.2/License.txt +24 -0
  79. data/vendor/bundle/gems/rspec-expectations-3.0.2/README.md +278 -0
  80. data/vendor/bundle/gems/rspec-mocks-3.0.2/.document +5 -0
  81. data/vendor/bundle/gems/rspec-mocks-3.0.2/.yardopts +6 -0
  82. data/vendor/bundle/gems/rspec-mocks-3.0.2/Changelog.md +733 -0
  83. data/vendor/bundle/gems/rspec-mocks-3.0.2/License.txt +24 -0
  84. data/vendor/bundle/gems/rspec-mocks-3.0.2/README.md +380 -0
  85. data/vendor/bundle/gems/rspec-support-3.0.2/Changelog.md +30 -0
  86. data/vendor/bundle/gems/rspec-support-3.0.2/LICENSE.txt +22 -0
  87. data/vendor/bundle/gems/rspec-support-3.0.2/README.md +17 -0
  88. data/vendor/bundle/specifications/diff-lcs-1.2.5.gemspec +68 -0
  89. data/vendor/bundle/specifications/rspec-3.0.0.gemspec +43 -0
  90. data/vendor/bundle/specifications/rspec-core-3.0.2.gemspec +66 -0
  91. data/vendor/bundle/specifications/rspec-expectations-3.0.2.gemspec +51 -0
  92. data/vendor/bundle/specifications/rspec-mocks-3.0.2.gemspec +48 -0
  93. data/vendor/bundle/specifications/rspec-support-3.0.2.gemspec +42 -0
  94. metadata +153 -0
@@ -0,0 +1,276 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'diff/lcs/block'
4
+
5
+ # A Hunk is a group of Blocks which overlap because of the context
6
+ # surrounding each block. (So if we're not using context, every hunk will
7
+ # contain one block.) Used in the diff program (bin/diff).
8
+ class Diff::LCS::Hunk
9
+ # Create a hunk using references to both the old and new data, as well as
10
+ # the piece of data.
11
+ def initialize(data_old, data_new, piece, flag_context, file_length_difference)
12
+ # At first, a hunk will have just one Block in it
13
+ @blocks = [ Diff::LCS::Block.new(piece) ]
14
+ if String.method_defined?(:encoding)
15
+ @preferred_data_encoding = data_old.fetch(0, data_new.fetch(0,'') ).encoding
16
+ end
17
+ @data_old = data_old
18
+ @data_new = data_new
19
+
20
+ before = after = file_length_difference
21
+ after += @blocks[0].diff_size
22
+ @file_length_difference = after # The caller must get this manually
23
+
24
+ # Save the start & end of each array. If the array doesn't exist (e.g.,
25
+ # we're only adding items in this block), then figure out the line
26
+ # number based on the line number of the other file and the current
27
+ # difference in file lengths.
28
+ if @blocks[0].remove.empty?
29
+ a1 = a2 = nil
30
+ else
31
+ a1 = @blocks[0].remove[0].position
32
+ a2 = @blocks[0].remove[-1].position
33
+ end
34
+
35
+ if @blocks[0].insert.empty?
36
+ b1 = b2 = nil
37
+ else
38
+ b1 = @blocks[0].insert[0].position
39
+ b2 = @blocks[0].insert[-1].position
40
+ end
41
+
42
+ @start_old = a1 || (b1 - before)
43
+ @start_new = b1 || (a1 + before)
44
+ @end_old = a2 || (b2 - after)
45
+ @end_new = b2 || (a2 + after)
46
+
47
+ self.flag_context = flag_context
48
+ end
49
+
50
+ attr_reader :blocks
51
+ attr_reader :start_old, :start_new
52
+ attr_reader :end_old, :end_new
53
+ attr_reader :file_length_difference
54
+
55
+ # Change the "start" and "end" fields to note that context should be added
56
+ # to this hunk.
57
+ attr_accessor :flag_context
58
+ undef :flag_context=;
59
+ def flag_context=(context) #:nodoc:
60
+ return if context.nil? or context.zero?
61
+
62
+ add_start = (context > @start_old) ? @start_old : context
63
+ @start_old -= add_start
64
+ @start_new -= add_start
65
+
66
+ if (@end_old + context) > @data_old.size
67
+ add_end = @data_old.size - @end_old
68
+ else
69
+ add_end = context
70
+ end
71
+ @end_old += add_end
72
+ @end_new += add_end
73
+ end
74
+
75
+ # Merges this hunk and the provided hunk together if they overlap. Returns
76
+ # a truthy value so that if there is no overlap, you can know the merge
77
+ # was skipped.
78
+ def merge(hunk)
79
+ if overlaps?(hunk)
80
+ @start_old = hunk.start_old
81
+ @start_new = hunk.start_new
82
+ blocks.unshift(*hunk.blocks)
83
+ else
84
+ nil
85
+ end
86
+ end
87
+ alias_method :unshift, :merge
88
+
89
+ # Determines whether there is an overlap between this hunk and the
90
+ # provided hunk. This will be true if the difference between the two hunks
91
+ # start or end positions is within one position of each other.
92
+ def overlaps?(hunk)
93
+ hunk and (((@start_old - hunk.end_old) <= 1) or
94
+ ((@start_new - hunk.end_new) <= 1))
95
+ end
96
+
97
+ # Returns a diff string based on a format.
98
+ def diff(format)
99
+ case format
100
+ when :old
101
+ old_diff
102
+ when :unified
103
+ unified_diff
104
+ when :context
105
+ context_diff
106
+ when :ed
107
+ self
108
+ when :reverse_ed, :ed_finish
109
+ ed_diff(format)
110
+ else
111
+ raise "Unknown diff format #{format}."
112
+ end
113
+ end
114
+
115
+ # Note that an old diff can't have any context. Therefore, we know that
116
+ # there's only one block in the hunk.
117
+ def old_diff
118
+ warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1
119
+ op_act = { "+" => 'a', "-" => 'd', "!" => "c" }
120
+
121
+ block = @blocks[0]
122
+
123
+ # Calculate item number range. Old diff range is just like a context
124
+ # diff range, except the ranges are on one line with the action between
125
+ # them.
126
+ s = encode("#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n")
127
+ # If removing anything, just print out all the remove lines in the hunk
128
+ # which is just all the remove lines in the block.
129
+ @data_old[@start_old .. @end_old].each { |e| s << encode("< ") + e + encode("\n") } unless block.remove.empty?
130
+ s << encode("---\n") if block.op == "!"
131
+ @data_new[@start_new .. @end_new].each { |e| s << encode("> ") + e + encode("\n") } unless block.insert.empty?
132
+ s
133
+ end
134
+ private :old_diff
135
+
136
+ def unified_diff
137
+ # Calculate item number range.
138
+ s = encode("@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n")
139
+
140
+ # Outlist starts containing the hunk of the old file. Removing an item
141
+ # just means putting a '-' in front of it. Inserting an item requires
142
+ # getting it from the new file and splicing it in. We splice in
143
+ # +num_added+ items. Remove blocks use +num_added+ because splicing
144
+ # changed the length of outlist.
145
+ #
146
+ # We remove +num_removed+ items. Insert blocks use +num_removed+
147
+ # because their item numbers -- corresponding to positions in the NEW
148
+ # file -- don't take removed items into account.
149
+ lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0
150
+
151
+ outlist = @data_old[lo .. hi].map { |e| e.insert(0, encode(' ')) }
152
+
153
+ @blocks.each do |block|
154
+ block.remove.each do |item|
155
+ op = item.action.to_s # -
156
+ offset = item.position - lo + num_added
157
+ outlist[offset][0, 1] = encode(op)
158
+ num_removed += 1
159
+ end
160
+ block.insert.each do |item|
161
+ op = item.action.to_s # +
162
+ offset = item.position - @start_new + num_removed
163
+ outlist[offset, 0] = encode(op) + @data_new[item.position]
164
+ num_added += 1
165
+ end
166
+ end
167
+
168
+ s << outlist.join(encode("\n"))
169
+ end
170
+ private :unified_diff
171
+
172
+ def context_diff
173
+ s = encode("***************\n")
174
+ s << encode("*** #{context_range(:old)} ****\n")
175
+ r = context_range(:new)
176
+
177
+ # Print out file 1 part for each block in context diff format if there
178
+ # are any blocks that remove items
179
+ lo, hi = @start_old, @end_old
180
+ removes = @blocks.select { |e| not e.remove.empty? }
181
+ if removes
182
+ outlist = @data_old[lo .. hi].map { |e| e.insert(0, encode(' ')) }
183
+
184
+ removes.each do |block|
185
+ block.remove.each do |item|
186
+ outlist[item.position - lo][0, 1] = encode(block.op) # - or !
187
+ end
188
+ end
189
+ s << outlist.join("\n")
190
+ end
191
+
192
+ s << encode("\n--- #{r} ----\n")
193
+ lo, hi = @start_new, @end_new
194
+ inserts = @blocks.select { |e| not e.insert.empty? }
195
+ if inserts
196
+ outlist = @data_new[lo .. hi].collect { |e| e.insert(0, encode(' ')) }
197
+ inserts.each do |block|
198
+ block.insert.each do |item|
199
+ outlist[item.position - lo][0, 1] = encode(block.op) # + or !
200
+ end
201
+ end
202
+ s << outlist.join("\n")
203
+ end
204
+ s
205
+ end
206
+ private :context_diff
207
+
208
+ def ed_diff(format)
209
+ op_act = { "+" => 'a', "-" => 'd', "!" => "c" }
210
+ warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1
211
+
212
+ if format == :reverse_ed
213
+ s = encode("#{op_act[@blocks[0].op]}#{context_range(:old)}\n")
214
+ else
215
+ s = encode("#{context_range(:old, ' ')}#{op_act[@blocks[0].op]}\n")
216
+ end
217
+
218
+ unless @blocks[0].insert.empty?
219
+ @data_new[@start_new .. @end_new].each { |e| s << e + encode("\n") }
220
+ s << encode(".\n")
221
+ end
222
+ s
223
+ end
224
+ private :ed_diff
225
+
226
+ # Generate a range of item numbers to print. Only print 1 number if the
227
+ # range has only one item in it. Otherwise, it's 'start,end'
228
+ def context_range(mode, op = ',')
229
+ case mode
230
+ when :old
231
+ s, e = (@start_old + 1), (@end_old + 1)
232
+ when :new
233
+ s, e = (@start_new + 1), (@end_new + 1)
234
+ end
235
+
236
+ (s < e) ? "#{s}#{op}#{e}" : "#{e}"
237
+ end
238
+ private :context_range
239
+
240
+ # Generate a range of item numbers to print for unified diff. Print number
241
+ # where block starts, followed by number of lines in the block
242
+ # (don't print number of lines if it's 1)
243
+ def unified_range(mode)
244
+ case mode
245
+ when :old
246
+ s, e = (@start_old + 1), (@end_old + 1)
247
+ when :new
248
+ s, e = (@start_new + 1), (@end_new + 1)
249
+ end
250
+
251
+ length = e - s + 1
252
+ first = (length < 2) ? e : s # "strange, but correct"
253
+ (length == 1) ? "#{first}" : "#{first},#{length}"
254
+ end
255
+ private :unified_range
256
+
257
+ if String.method_defined?(:encoding)
258
+ def encode(literal, target_encoding = @preferred_data_encoding)
259
+ literal.encode target_encoding
260
+ end
261
+
262
+ def encode_as(string, *args)
263
+ args.map { |arg| arg.encode(string.encoding) }
264
+ end
265
+ else
266
+ def encode(literal, target_encoding = nil)
267
+ literal
268
+ end
269
+ def encode_as(string, *args)
270
+ args
271
+ end
272
+ end
273
+
274
+ private :encode
275
+ private :encode_as
276
+ end
@@ -0,0 +1,301 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ class << Diff::LCS
4
+ def diff_traversal(method, seq1, seq2, callbacks, &block)
5
+ callbacks = callbacks_for(callbacks)
6
+ case method
7
+ when :diff
8
+ traverse_sequences(seq1, seq2, callbacks)
9
+ when :sdiff
10
+ traverse_balanced(seq1, seq2, callbacks)
11
+ end
12
+ callbacks.finish if callbacks.respond_to? :finish
13
+
14
+ if block
15
+ callbacks.diffs.map do |hunk|
16
+ if hunk.kind_of? Array
17
+ hunk.map { |hunk_block| block[hunk_block] }
18
+ else
19
+ block[hunk]
20
+ end
21
+ end
22
+ else
23
+ callbacks.diffs
24
+ end
25
+ end
26
+ private :diff_traversal
27
+ end
28
+
29
+ module Diff::LCS::Internals # :nodoc:
30
+ end
31
+
32
+ class << Diff::LCS::Internals
33
+ # Compute the longest common subsequence between the sequenced
34
+ # Enumerables +a+ and +b+. The result is an array whose contents is such
35
+ # that
36
+ #
37
+ # result = Diff::LCS::Internals.lcs(a, b)
38
+ # result.each_with_index do |e, i|
39
+ # assert_equal(a[i], b[e]) unless e.nil?
40
+ # end
41
+ def lcs(a, b)
42
+ a_start = b_start = 0
43
+ a_finish = a.size - 1
44
+ b_finish = b.size - 1
45
+ vector = []
46
+
47
+ # Prune off any common elements at the beginning...
48
+ while ((a_start <= a_finish) and (b_start <= b_finish) and
49
+ (a[a_start] == b[b_start]))
50
+ vector[a_start] = b_start
51
+ a_start += 1
52
+ b_start += 1
53
+ end
54
+ b_start = a_start
55
+
56
+ # Now the end...
57
+ while ((a_start <= a_finish) and (b_start <= b_finish) and
58
+ (a[a_finish] == b[b_finish]))
59
+ vector[a_finish] = b_finish
60
+ a_finish -= 1
61
+ b_finish -= 1
62
+ end
63
+
64
+ # Now, compute the equivalence classes of positions of elements.
65
+ b_matches = position_hash(b, b_start..b_finish)
66
+
67
+ thresh = []
68
+ links = []
69
+ string = a.kind_of?(String)
70
+
71
+ (a_start .. a_finish).each do |i|
72
+ ai = string ? a[i, 1] : a[i]
73
+ bm = b_matches[ai]
74
+ k = nil
75
+ bm.reverse_each do |j|
76
+ if k and (thresh[k] > j) and (thresh[k - 1] < j)
77
+ thresh[k] = j
78
+ else
79
+ k = replace_next_larger(thresh, j, k)
80
+ end
81
+ links[k] = [ (k > 0) ? links[k - 1] : nil, i, j ] unless k.nil?
82
+ end
83
+ end
84
+
85
+ unless thresh.empty?
86
+ link = links[thresh.size - 1]
87
+ while not link.nil?
88
+ vector[link[1]] = link[2]
89
+ link = link[0]
90
+ end
91
+ end
92
+
93
+ vector
94
+ end
95
+
96
+ # This method will analyze the provided patchset to provide a
97
+ # single-pass normalization (conversion of the array form of
98
+ # Diff::LCS::Change objects to the object form of same) and detection of
99
+ # whether the patchset represents changes to be made.
100
+ def analyze_patchset(patchset, depth = 0)
101
+ raise "Patchset too complex" if depth > 1
102
+
103
+ has_changes = false
104
+
105
+ # Format:
106
+ # [ # patchset
107
+ # # hunk (change)
108
+ # [ # hunk
109
+ # # change
110
+ # ]
111
+ # ]
112
+
113
+ patchset = patchset.map do |hunk|
114
+ case hunk
115
+ when Diff::LCS::Change
116
+ has_changes ||= !hunk.unchanged?
117
+ hunk
118
+ when Array
119
+ # Detect if the 'hunk' is actually an array-format
120
+ # Change object.
121
+ if Diff::LCS::Change.valid_action? hunk[0]
122
+ hunk = Diff::LCS::Change.from_a(hunk)
123
+ has_changes ||= !hunk.unchanged?
124
+ hunk
125
+ else
126
+ with_changes, hunk = analyze_patchset(hunk, depth + 1)
127
+ has_changes ||= with_changes
128
+ hunk.flatten
129
+ end
130
+ else
131
+ raise ArgumentError, "Cannot normalise a hunk of class #{hunk.class}."
132
+ end
133
+ end
134
+
135
+ [ has_changes, patchset.flatten(1) ]
136
+ end
137
+
138
+ # Examine the patchset and the source to see in which direction the
139
+ # patch should be applied.
140
+ #
141
+ # WARNING: By default, this examines the whole patch, so this could take
142
+ # some time. This also works better with Diff::LCS::ContextChange or
143
+ # Diff::LCS::Change as its source, as an array will cause the creation
144
+ # of one of the above.
145
+ #
146
+ # Note: This will be deprecated as a public function in a future release.
147
+ def intuit_diff_direction(src, patchset, limit = nil)
148
+ string = src.kind_of?(String)
149
+ count = left_match = left_miss = right_match = right_miss = 0
150
+
151
+ patchset.each do |change|
152
+ count += 1
153
+
154
+ case change
155
+ when Diff::LCS::ContextChange
156
+ le = string ? src[change.old_position, 1] : src[change.old_position]
157
+ re = string ? src[change.new_position, 1] : src[change.new_position]
158
+
159
+ case change.action
160
+ when '-' # Remove details from the old string
161
+ if le == change.old_element
162
+ left_match += 1
163
+ else
164
+ left_miss += 1
165
+ end
166
+ when '+'
167
+ if re == change.new_element
168
+ right_match += 1
169
+ else
170
+ right_miss += 1
171
+ end
172
+ when '='
173
+ left_miss += 1 if le != change.old_element
174
+ right_miss += 1 if re != change.new_element
175
+ when '!'
176
+ if le == change.old_element
177
+ left_match += 1
178
+ else
179
+ if re == change.new_element
180
+ right_match += 1
181
+ else
182
+ left_miss += 1
183
+ right_miss += 1
184
+ end
185
+ end
186
+ end
187
+ when Diff::LCS::Change
188
+ # With a simplistic change, we can't tell the difference between
189
+ # the left and right on '!' actions, so we ignore those. On '='
190
+ # actions, if there's a miss, we miss both left and right.
191
+ element = string ? src[change.position, 1] : src[change.position]
192
+
193
+ case change.action
194
+ when '-'
195
+ if element == change.element
196
+ left_match += 1
197
+ else
198
+ left_miss += 1
199
+ end
200
+ when '+'
201
+ if element == change.element
202
+ right_match += 1
203
+ else
204
+ right_miss += 1
205
+ end
206
+ when '='
207
+ if element != change.element
208
+ left_miss += 1
209
+ right_miss += 1
210
+ end
211
+ end
212
+ end
213
+
214
+ break if (not limit.nil?) && (count > limit)
215
+ end
216
+
217
+ no_left = (left_match == 0) && (left_miss > 0)
218
+ no_right = (right_match == 0) && (right_miss > 0)
219
+
220
+ case [no_left, no_right]
221
+ when [false, true]
222
+ :patch
223
+ when [true, false]
224
+ :unpatch
225
+ else
226
+ case left_match <=> right_match
227
+ when 1
228
+ :patch
229
+ when -1
230
+ :unpatch
231
+ else
232
+ raise "The provided patchset does not appear to apply to the provided value as either source or destination value."
233
+ end
234
+ end
235
+ end
236
+
237
+ # Find the place at which +value+ would normally be inserted into the
238
+ # Enumerable. If that place is already occupied by +value+, do nothing
239
+ # and return +nil+. If the place does not exist (i.e., it is off the end
240
+ # of the Enumerable), add it to the end. Otherwise, replace the element
241
+ # at that point with +value+. It is assumed that the Enumerable's values
242
+ # are numeric.
243
+ #
244
+ # This operation preserves the sort order.
245
+ def replace_next_larger(enum, value, last_index = nil)
246
+ # Off the end?
247
+ if enum.empty? or (value > enum[-1])
248
+ enum << value
249
+ return enum.size - 1
250
+ end
251
+
252
+ # Binary search for the insertion point
253
+ last_index ||= enum.size
254
+ first_index = 0
255
+ while (first_index <= last_index)
256
+ i = (first_index + last_index) >> 1
257
+
258
+ found = enum[i]
259
+
260
+ if value == found
261
+ return nil
262
+ elsif value > found
263
+ first_index = i + 1
264
+ else
265
+ last_index = i - 1
266
+ end
267
+ end
268
+
269
+ # The insertion point is in first_index; overwrite the next larger
270
+ # value.
271
+ enum[first_index] = value
272
+ return first_index
273
+ end
274
+ private :replace_next_larger
275
+
276
+ # If +vector+ maps the matching elements of another collection onto this
277
+ # Enumerable, compute the inverse of +vector+ that maps this Enumerable
278
+ # onto the collection. (Currently unused.)
279
+ def inverse_vector(a, vector)
280
+ inverse = a.dup
281
+ (0...vector.size).each do |i|
282
+ inverse[vector[i]] = i unless vector[i].nil?
283
+ end
284
+ inverse
285
+ end
286
+ private :inverse_vector
287
+
288
+ # Returns a hash mapping each element of an Enumerable to the set of
289
+ # positions it occupies in the Enumerable, optionally restricted to the
290
+ # elements specified in the range of indexes specified by +interval+.
291
+ def position_hash(enum, interval)
292
+ string = enum.kind_of?(String)
293
+ hash = Hash.new { |h, k| h[k] = [] }
294
+ interval.each do |i|
295
+ k = string ? enum[i, 1] : enum[i]
296
+ hash[k] << i
297
+ end
298
+ hash
299
+ end
300
+ private :position_hash
301
+ end