redis-diff_match_patch 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in redis-diff_match_patch.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Alex McHale (alex@anticlever.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ Redis: Diff Match Patch
2
+ =======================
3
+
4
+ ## DESCRIPTION
5
+
6
+ Redis: Diff Match Patch is a library for using [Google's diff-match-patch][1]
7
+ on a Redis server.
8
+
9
+ This library uses the Lua port included with diff-match-patch to atomically
10
+ calculate and apply patches of string values stored in Redis.
11
+
12
+ ## PREREQUISITES
13
+
14
+ This library requires a Redis server with Lua scripting support (EVAL and
15
+ EVALSHA commands). This support was added in Redis 2.6.
16
+
17
+ ## INSTALLATION
18
+
19
+ ### To install manually from RubyGems:
20
+
21
+ gem install redis-diff_match_patch
22
+
23
+ ### To use in a project with Bundler, edit your Gemfile to include:
24
+
25
+ gem 'redis-diff_match_patch'
26
+
27
+ ## API
28
+
29
+ dmp = Redis::DiffMatchPatch.new(REDIS_CLIENT)
30
+
31
+ # Calculate a diff of two keys
32
+ dmp.diff ORIGINAL_KEY, CURRENT_KEY, DIFF_OUTPUT_KEY
33
+
34
+ # Patch a key
35
+ dmp.patch ORIGINAL_KEY, DIFF_KEY, RESULT_OUTPUT_KEY
36
+
37
+ # Perform a 3-way merge
38
+ dmp.merge ANCESTOR_KEY, KEY1, KEY2, RESULT_OUTPUT_KEY
39
+
40
+ The output keys are optional. All API methods will return the result value.
41
+
42
+ ## EXAMPLES
43
+
44
+ ### Calculate the diff of an original document and a current version of that document.
45
+
46
+ redis = Redis.new
47
+ dmp = Redis::DiffMatchPatch.new redis
48
+
49
+ redis["original"] = "hello world"
50
+ redis["doc"] = "Hello, world!"
51
+
52
+ dmp.diff "original", "doc", "diff"
53
+
54
+ redis["diff"] #=> "@@ -1,11 +1,13 @@\n-h\n+H\n ello\n+,\n world\n+!\n"
55
+
56
+ ### Perform a 3-way merge on two documents that are variations from an original source.
57
+
58
+ redis = Redis.new
59
+ dmp = Redis::DiffMatchPatch.new redis
60
+
61
+ redis["original"] = "hello world"
62
+ redis["doc1"] = "Howdy, world!"
63
+ redis["doc2"] = "hello my friends"
64
+
65
+ dmp.merge "original", "doc1", "doc2", "result"
66
+
67
+ redis["result"] #=> "Howdy, my friends!"
68
+
69
+ ## REFERENCES
70
+
71
+ * [Google's diff-match-patch][1] provides the meat of the functionality in this library.
72
+ * [Dialectronics BinDecHex][2] for providing functions to enable diff-match-patch on Redis.
73
+
74
+ [1]: http://code.google.com/p/google-diff-match-patch/
75
+ [2]: http://www.dialectronics.com/Lua/
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ task :default => :test
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'lib'
8
+ t.libs << 'test'
9
+ t.pattern = 'test/*_test.rb'
10
+ t.verbose = true
11
+ end
@@ -0,0 +1,542 @@
1
+ --[[
2
+ /*
3
+ * Copyright (c) 2007 Tim Kelly/Dialectronics
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
10
+ * persons to whom the Software is furnished to do so, subject to the
11
+ * following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+ --]]
26
+
27
+ --[[
28
+ /*
29
+ * Copyright (c) 2007 Tim Kelly/Dialectronics
30
+ *
31
+ * Permission is hereby granted, free of charge, to any person obtaining
32
+ * a copy of this software and associated documentation files (the
33
+ * "Software"), to deal in the Software without restriction, including
34
+ * without limitation the rights to use, copy, modify, merge, publish,
35
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
36
+ * persons to whom the Software is furnished to do so, subject to the
37
+ * following conditions:
38
+ *
39
+ * The above copyright notice and this permission notice shall be
40
+ * included in all copies or substantial portions of the Software.
41
+ *
42
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
45
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
46
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
47
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
48
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
49
+ */
50
+
51
+ --]]
52
+
53
+ module(..., package.seeall);
54
+
55
+ local hex2bin = {
56
+ ["0"] = "0000",
57
+ ["1"] = "0001",
58
+ ["2"] = "0010",
59
+ ["3"] = "0011",
60
+ ["4"] = "0100",
61
+ ["5"] = "0101",
62
+ ["6"] = "0110",
63
+ ["7"] = "0111",
64
+ ["8"] = "1000",
65
+ ["9"] = "1001",
66
+ ["a"] = "1010",
67
+ ["b"] = "1011",
68
+ ["c"] = "1100",
69
+ ["d"] = "1101",
70
+ ["e"] = "1110",
71
+ ["f"] = "1111"
72
+ }
73
+
74
+
75
+
76
+ local bin2hex = {
77
+ ["0000"] = "0",
78
+ ["0001"] = "1",
79
+ ["0010"] = "2",
80
+ ["0011"] = "3",
81
+ ["0100"] = "4",
82
+ ["0101"] = "5",
83
+ ["0110"] = "6",
84
+ ["0111"] = "7",
85
+ ["1000"] = "8",
86
+ ["1001"] = "9",
87
+ ["1010"] = "A",
88
+ ["1011"] = "B",
89
+ ["1100"] = "C",
90
+ ["1101"] = "D",
91
+ ["1110"] = "E",
92
+ ["1111"] = "F"
93
+ }
94
+
95
+ --[[
96
+ local dec2hex = {
97
+ ["0"] = "0",
98
+ ["1"] = "1",
99
+ ["2"] = "2",
100
+ ["3"] = "3",
101
+ ["4"] = "4",
102
+ ["5"] = "5",
103
+ ["6"] = "6",
104
+ ["7"] = "7",
105
+ ["8"] = "8",
106
+ ["9"] = "9",
107
+ ["10"] = "A",
108
+ ["11"] = "B",
109
+ ["12"] = "C",
110
+ ["13"] = "D",
111
+ ["14"] = "E",
112
+ ["15"] = "F"
113
+ }
114
+ --]]
115
+
116
+
117
+ -- These functions are big-endian and take up to 32 bits
118
+
119
+ -- Hex2Bin
120
+ -- Bin2Hex
121
+ -- Hex2Dec
122
+ -- Dec2Hex
123
+ -- Bin2Dec
124
+ -- Dec2Bin
125
+
126
+
127
+ function Hex2Bin(s)
128
+
129
+ -- s -> hexadecimal string
130
+
131
+ local ret = ""
132
+ local i = 0
133
+
134
+
135
+ for i in string.gfind(s, ".") do
136
+ i = string.lower(i)
137
+
138
+ ret = ret..hex2bin[i]
139
+
140
+ end
141
+
142
+ return ret
143
+ end
144
+
145
+
146
+ function Bin2Hex(s)
147
+
148
+ -- s -> binary string
149
+
150
+ local l = 0
151
+ local h = ""
152
+ local b = ""
153
+ local rem
154
+
155
+ l = string.len(s)
156
+ rem = l % 4
157
+ l = l-1
158
+ h = ""
159
+
160
+ -- need to prepend zeros to eliminate mod 4
161
+ if (rem > 0) then
162
+ s = string.rep("0", 4 - rem)..s
163
+ end
164
+
165
+ for i = 1, l, 4 do
166
+ b = string.sub(s, i, i+3)
167
+ h = h..bin2hex[b]
168
+ end
169
+
170
+ return h
171
+
172
+ end
173
+
174
+
175
+ function Bin2Dec(s)
176
+
177
+ -- s -> binary string
178
+
179
+ local num = 0
180
+ local ex = string.len(s) - 1
181
+ local l = 0
182
+
183
+ l = ex + 1
184
+ for i = 1, l do
185
+ b = string.sub(s, i, i)
186
+ if b == "1" then
187
+ num = num + 2^ex
188
+ end
189
+ ex = ex - 1
190
+ end
191
+
192
+ return string.format("%u", num)
193
+
194
+ end
195
+
196
+
197
+
198
+ function Dec2Bin(s, num)
199
+
200
+ -- s -> Base10 string
201
+ -- num -> string length to extend to
202
+
203
+ local n
204
+
205
+ if (num == nil) then
206
+ n = 0
207
+ else
208
+ n = num
209
+ end
210
+
211
+ s = string.format("%x", s)
212
+
213
+ s = Hex2Bin(s)
214
+
215
+ while string.len(s) < n do
216
+ s = "0"..s
217
+ end
218
+
219
+ return s
220
+
221
+ end
222
+
223
+
224
+
225
+
226
+ function Hex2Dec(s)
227
+
228
+ -- s -> hexadecimal string
229
+
230
+ local s = Hex2Bin(s)
231
+
232
+ return Bin2Dec(s)
233
+
234
+ end
235
+
236
+
237
+
238
+ function Dec2Hex(s)
239
+
240
+ -- s -> Base10 string
241
+
242
+ s = string.format("%x", s)
243
+
244
+ return s
245
+
246
+ end
247
+
248
+
249
+
250
+
251
+ -- These functions are big-endian and will extend to 32 bits
252
+
253
+ -- BMAnd
254
+ -- BMNAnd
255
+ -- BMOr
256
+ -- BMXOr
257
+ -- BMNot
258
+
259
+
260
+ function BMAnd(v, m)
261
+
262
+ -- v -> hex string to be masked
263
+ -- m -> hex string mask
264
+
265
+ -- s -> hex string as masked
266
+
267
+ -- bv -> binary string of v
268
+ -- bm -> binary string mask
269
+
270
+ local bv = Hex2Bin(v)
271
+ local bm = Hex2Bin(m)
272
+
273
+ local i = 0
274
+ local s = ""
275
+
276
+ while (string.len(bv) < 32) do
277
+ bv = "0000"..bv
278
+ end
279
+
280
+ while (string.len(bm) < 32) do
281
+ bm = "0000"..bm
282
+ end
283
+
284
+
285
+ for i = 1, 32 do
286
+ cv = string.sub(bv, i, i)
287
+ cm = string.sub(bm, i, i)
288
+ if cv == cm then
289
+ if cv == "1" then
290
+ s = s.."1"
291
+ else
292
+ s = s.."0"
293
+ end
294
+ else
295
+ s = s.."0"
296
+
297
+ end
298
+ end
299
+
300
+ return Bin2Hex(s)
301
+
302
+ end
303
+
304
+
305
+ function BMNAnd(v, m)
306
+
307
+ -- v -> hex string to be masked
308
+ -- m -> hex string mask
309
+
310
+ -- s -> hex string as masked
311
+
312
+ -- bv -> binary string of v
313
+ -- bm -> binary string mask
314
+
315
+ local bv = Hex2Bin(v)
316
+ local bm = Hex2Bin(m)
317
+
318
+ local i = 0
319
+ local s = ""
320
+
321
+ while (string.len(bv) < 32) do
322
+ bv = "0000"..bv
323
+ end
324
+
325
+ while (string.len(bm) < 32) do
326
+ bm = "0000"..bm
327
+ end
328
+
329
+
330
+ for i = 1, 32 do
331
+ cv = string.sub(bv, i, i)
332
+ cm = string.sub(bm, i, i)
333
+ if cv == cm then
334
+ if cv == "1" then
335
+ s = s.."0"
336
+ else
337
+ s = s.."1"
338
+ end
339
+ else
340
+ s = s.."1"
341
+
342
+ end
343
+ end
344
+
345
+ return Bin2Hex(s)
346
+
347
+ end
348
+
349
+
350
+
351
+ function BMOr(v, m)
352
+
353
+ -- v -> hex string to be masked
354
+ -- m -> hex string mask
355
+
356
+ -- s -> hex string as masked
357
+
358
+ -- bv -> binary string of v
359
+ -- bm -> binary string mask
360
+
361
+ local bv = Hex2Bin(v)
362
+ local bm = Hex2Bin(m)
363
+
364
+ local i = 0
365
+ local s = ""
366
+
367
+ while (string.len(bv) < 32) do
368
+ bv = "0000"..bv
369
+ end
370
+
371
+ while (string.len(bm) < 32) do
372
+ bm = "0000"..bm
373
+ end
374
+
375
+
376
+ for i = 1, 32 do
377
+ cv = string.sub(bv, i, i)
378
+ cm = string.sub(bm, i, i)
379
+ if cv == "1" then
380
+ s = s.."1"
381
+ elseif cm == "1" then
382
+ s = s.."1"
383
+ else
384
+ s = s.."0"
385
+ end
386
+ end
387
+
388
+ return Bin2Hex(s)
389
+
390
+ end
391
+
392
+ function BMXOr(v, m)
393
+
394
+ -- v -> hex string to be masked
395
+ -- m -> hex string mask
396
+
397
+ -- s -> hex string as masked
398
+
399
+ -- bv -> binary string of v
400
+ -- bm -> binary string mask
401
+
402
+ local bv = Hex2Bin(v)
403
+ local bm = Hex2Bin(m)
404
+
405
+ local i = 0
406
+ local s = ""
407
+
408
+ while (string.len(bv) < 32) do
409
+ bv = "0000"..bv
410
+ end
411
+
412
+ while (string.len(bm) < 32) do
413
+ bm = "0000"..bm
414
+ end
415
+
416
+
417
+ for i = 1, 32 do
418
+ cv = string.sub(bv, i, i)
419
+ cm = string.sub(bm, i, i)
420
+ if cv == "1" then
421
+ if cm == "0" then
422
+ s = s.."1"
423
+ else
424
+ s = s.."0"
425
+ end
426
+ elseif cm == "1" then
427
+ if cv == "0" then
428
+ s = s.."1"
429
+ else
430
+ s = s.."0"
431
+ end
432
+ else
433
+ -- cv and cm == "0"
434
+ s = s.."0"
435
+ end
436
+ end
437
+
438
+ return Bin2Hex(s)
439
+
440
+ end
441
+
442
+
443
+ function BMNot(v, m)
444
+
445
+ -- v -> hex string to be masked
446
+ -- m -> hex string mask
447
+
448
+ -- s -> hex string as masked
449
+
450
+ -- bv -> binary string of v
451
+ -- bm -> binary string mask
452
+
453
+ local bv = Hex2Bin(v)
454
+ local bm = Hex2Bin(m)
455
+
456
+ local i = 0
457
+ local s = ""
458
+
459
+ while (string.len(bv) < 32) do
460
+ bv = "0000"..bv
461
+ end
462
+
463
+ while (string.len(bm) < 32) do
464
+ bm = "0000"..bm
465
+ end
466
+
467
+
468
+ for i = 1, 32 do
469
+ cv = string.sub(bv, i, i)
470
+ cm = string.sub(bm, i, i)
471
+ if cm == "1" then
472
+ if cv == "1" then
473
+ -- turn off
474
+ s = s.."0"
475
+ else
476
+ -- turn on
477
+ s = s.."1"
478
+ end
479
+ else
480
+ -- leave untouched
481
+ s = s..cv
482
+
483
+ end
484
+ end
485
+
486
+ return Bin2Hex(s)
487
+
488
+ end
489
+
490
+
491
+ -- these functions shift right and left, adding zeros to lost or gained bits
492
+ -- returned values are 32 bits long
493
+
494
+ -- BShRight(v, nb)
495
+ -- BShLeft(v, nb)
496
+
497
+
498
+ function BShRight(v, nb)
499
+
500
+ -- v -> hexstring value to be shifted
501
+ -- nb -> number of bits to shift to the right
502
+
503
+ -- s -> binary string of v
504
+
505
+ local s = Hex2Bin(v)
506
+
507
+ while (string.len(s) < 32) do
508
+ s = "0000"..s
509
+ end
510
+
511
+ s = string.sub(s, 1, 32 - nb)
512
+
513
+ while (string.len(s) < 32) do
514
+ s = "0"..s
515
+ end
516
+
517
+ return Bin2Hex(s)
518
+
519
+ end
520
+
521
+ function BShLeft(v, nb)
522
+
523
+ -- v -> hexstring value to be shifted
524
+ -- nb -> number of bits to shift to the right
525
+
526
+ -- s -> binary string of v
527
+
528
+ local s = Hex2Bin(v)
529
+
530
+ while (string.len(s) < 32) do
531
+ s = "0000"..s
532
+ end
533
+
534
+ s = string.sub(s, nb + 1, 32)
535
+
536
+ while (string.len(s) < 32) do
537
+ s = s.."0"
538
+ end
539
+
540
+ return Bin2Hex(s)
541
+
542
+ end