strokedb 0.0.2
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/CONTRIBUTORS +7 -0
- data/CREDITS +13 -0
- data/README +44 -0
- data/bin/sdbc +2 -0
- data/lib/config/config.rb +161 -0
- data/lib/data_structures/inverted_list.rb +297 -0
- data/lib/data_structures/point_query.rb +24 -0
- data/lib/data_structures/skiplist.rb +302 -0
- data/lib/document/associations.rb +107 -0
- data/lib/document/callback.rb +11 -0
- data/lib/document/coercions.rb +57 -0
- data/lib/document/delete.rb +28 -0
- data/lib/document/document.rb +684 -0
- data/lib/document/meta.rb +261 -0
- data/lib/document/slot.rb +199 -0
- data/lib/document/util.rb +27 -0
- data/lib/document/validations.rb +704 -0
- data/lib/document/versions.rb +106 -0
- data/lib/document/virtualize.rb +82 -0
- data/lib/init.rb +57 -0
- data/lib/stores/chainable_storage.rb +57 -0
- data/lib/stores/inverted_list_index/inverted_list_file_storage.rb +56 -0
- data/lib/stores/inverted_list_index/inverted_list_index.rb +49 -0
- data/lib/stores/remote_store.rb +172 -0
- data/lib/stores/skiplist_store/chunk.rb +119 -0
- data/lib/stores/skiplist_store/chunk_storage.rb +21 -0
- data/lib/stores/skiplist_store/file_chunk_storage.rb +44 -0
- data/lib/stores/skiplist_store/memory_chunk_storage.rb +37 -0
- data/lib/stores/skiplist_store/skiplist_store.rb +217 -0
- data/lib/stores/store.rb +5 -0
- data/lib/sync/chain_sync.rb +38 -0
- data/lib/sync/diff.rb +126 -0
- data/lib/sync/lamport_timestamp.rb +81 -0
- data/lib/sync/store_sync.rb +79 -0
- data/lib/sync/stroke_diff/array.rb +102 -0
- data/lib/sync/stroke_diff/default.rb +21 -0
- data/lib/sync/stroke_diff/hash.rb +186 -0
- data/lib/sync/stroke_diff/string.rb +116 -0
- data/lib/sync/stroke_diff/stroke_diff.rb +9 -0
- data/lib/util/blankslate.rb +42 -0
- data/lib/util/ext/blank.rb +50 -0
- data/lib/util/ext/enumerable.rb +36 -0
- data/lib/util/ext/fixnum.rb +16 -0
- data/lib/util/ext/hash.rb +22 -0
- data/lib/util/ext/object.rb +8 -0
- data/lib/util/ext/string.rb +35 -0
- data/lib/util/inflect.rb +217 -0
- data/lib/util/java_util.rb +9 -0
- data/lib/util/lazy_array.rb +54 -0
- data/lib/util/lazy_mapping_array.rb +64 -0
- data/lib/util/lazy_mapping_hash.rb +46 -0
- data/lib/util/serialization.rb +29 -0
- data/lib/util/trigger_partition.rb +136 -0
- data/lib/util/util.rb +38 -0
- data/lib/util/xml.rb +6 -0
- data/lib/view/view.rb +55 -0
- data/script/console +70 -0
- data/strokedb.rb +75 -0
- metadata +148 -0
data/lib/util/inflect.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
# from the English gem (http://english.rubyforge.org/)
|
2
|
+
# http://english.rubyforge.org/rdoc/classes/English/Inflect.html
|
3
|
+
#
|
4
|
+
# last updated from http://english.rubyforge.org/svn/trunk/lib/english/inflect.rb on 3-31-2008
|
5
|
+
|
6
|
+
module English
|
7
|
+
|
8
|
+
# = English Nouns Number Inflection.
|
9
|
+
#
|
10
|
+
# This module provides english singular <-> plural noun inflections.
|
11
|
+
module Inflect
|
12
|
+
|
13
|
+
@singular_of = {}
|
14
|
+
@plural_of = {}
|
15
|
+
|
16
|
+
@singular_rules = []
|
17
|
+
@plural_rules = []
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# Define a general exception.
|
21
|
+
def word(singular, plural=nil)
|
22
|
+
plural = singular unless plural
|
23
|
+
singular_word(singular, plural)
|
24
|
+
plural_word(singular, plural)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Define a singularization exception.
|
28
|
+
def singular_word(singular, plural)
|
29
|
+
@singular_of[plural] = singular
|
30
|
+
end
|
31
|
+
|
32
|
+
# Define a pluralization exception.
|
33
|
+
def plural_word(singular, plural)
|
34
|
+
@plural_of[singular] = plural
|
35
|
+
end
|
36
|
+
|
37
|
+
# Define a general rule.
|
38
|
+
def rule(singular, plural)
|
39
|
+
singular_rule(singular, plural)
|
40
|
+
plural_rule(singular, plural)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Define a singularization rule.
|
44
|
+
def singular_rule(singular, plural)
|
45
|
+
@singular_rules << [singular, plural]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Define a plurualization rule.
|
49
|
+
def plural_rule(singular, plural)
|
50
|
+
@plural_rules << [singular, plural]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Read prepared singularization rules.
|
54
|
+
def singularization_rules
|
55
|
+
return @singularization_rules if @singularization_rules
|
56
|
+
sorted = @singular_rules.sort_by{ |s, p| "#{p}".size }.reverse
|
57
|
+
@singularization_rules = sorted.collect do |s, p|
|
58
|
+
[ /#{p}$/, "#{s}" ]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Read prepared pluralization rules.
|
63
|
+
def pluralization_rules
|
64
|
+
return @pluralization_rules if @pluralization_rules
|
65
|
+
sorted = @plural_rules.sort_by{ |s, p| "#{s}".size }.reverse
|
66
|
+
@pluralization_rules = sorted.collect do |s, p|
|
67
|
+
[ /#{s}$/, "#{p}" ]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
def plural_of
|
73
|
+
@plural_of
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
def singular_of
|
78
|
+
@singular_of
|
79
|
+
end
|
80
|
+
|
81
|
+
# Convert an English word from plurel to singular.
|
82
|
+
#
|
83
|
+
# "boys".singular #=> boy
|
84
|
+
# "tomatoes".singular #=> tomato
|
85
|
+
#
|
86
|
+
def singular(word)
|
87
|
+
if result = singular_of[word]
|
88
|
+
return result.dup
|
89
|
+
end
|
90
|
+
result = word.dup
|
91
|
+
singularization_rules.each do |(match, replacement)|
|
92
|
+
break if result.gsub!(match, replacement)
|
93
|
+
end
|
94
|
+
return result
|
95
|
+
end
|
96
|
+
|
97
|
+
# Alias for #singular (a Railism).
|
98
|
+
#
|
99
|
+
alias_method(:singularize, :singular)
|
100
|
+
|
101
|
+
# Convert an English word from singular to plurel.
|
102
|
+
#
|
103
|
+
# "boy".plural #=> boys
|
104
|
+
# "tomato".plural #=> tomatoes
|
105
|
+
#
|
106
|
+
def plural(word)
|
107
|
+
if result = plural_of[word]
|
108
|
+
return result.dup
|
109
|
+
end
|
110
|
+
#return self.dup if /s$/ =~ self # ???
|
111
|
+
result = word.dup
|
112
|
+
pluralization_rules.each do |(match, replacement)|
|
113
|
+
break if result.gsub!(match, replacement)
|
114
|
+
end
|
115
|
+
return result
|
116
|
+
end
|
117
|
+
|
118
|
+
# Alias for #plural (a Railism).
|
119
|
+
alias_method(:pluralize, :plural)
|
120
|
+
end
|
121
|
+
|
122
|
+
# One argument means singular and plural are the same.
|
123
|
+
|
124
|
+
word 'equipment'
|
125
|
+
word 'information'
|
126
|
+
word 'money'
|
127
|
+
word 'species'
|
128
|
+
word 'series'
|
129
|
+
word 'fish'
|
130
|
+
word 'sheep'
|
131
|
+
word 'moose'
|
132
|
+
word 'hovercraft'
|
133
|
+
|
134
|
+
# Two arguments defines a singular and plural exception.
|
135
|
+
|
136
|
+
word 'Swiss' , 'Swiss'
|
137
|
+
word 'life' , 'lives'
|
138
|
+
word 'wife' , 'wives'
|
139
|
+
word 'virus' , 'viri'
|
140
|
+
word 'octopus' , 'octopi'
|
141
|
+
word 'goose' , 'geese'
|
142
|
+
word 'criterion' , 'criteria'
|
143
|
+
word 'alias' , 'aliases'
|
144
|
+
word 'status' , 'statuses'
|
145
|
+
word 'axis' , 'axes'
|
146
|
+
word 'crisis' , 'crises'
|
147
|
+
word 'testis' , 'testes'
|
148
|
+
word 'child' , 'children'
|
149
|
+
word 'person' , 'people'
|
150
|
+
word 'potato' , 'potatoes'
|
151
|
+
word 'tomato' , 'tomatoes'
|
152
|
+
word 'buffalo' , 'buffaloes'
|
153
|
+
word 'torpedo' , 'torpedoes'
|
154
|
+
word 'quiz' , 'quizes'
|
155
|
+
word 'matrix' , 'matrices'
|
156
|
+
word 'vertex' , 'vetices'
|
157
|
+
word 'index' , 'indices'
|
158
|
+
word 'ox' , 'oxen'
|
159
|
+
word 'mouse' , 'mice'
|
160
|
+
word 'louse' , 'lice'
|
161
|
+
word 'thesis' , 'theses'
|
162
|
+
word 'thief' , 'thieves'
|
163
|
+
word 'analysis' , 'analyses'
|
164
|
+
|
165
|
+
# One-way singularization exception (convert plural to singular).
|
166
|
+
|
167
|
+
singular_word 'cactus', 'cacti'
|
168
|
+
|
169
|
+
# General rules.
|
170
|
+
|
171
|
+
rule 'hive' , 'hives'
|
172
|
+
rule 'rf' , 'rves'
|
173
|
+
rule 'af' , 'aves'
|
174
|
+
rule 'ero' , 'eroes'
|
175
|
+
rule 'man' , 'men'
|
176
|
+
rule 'ch' , 'ches'
|
177
|
+
rule 'sh' , 'shes'
|
178
|
+
rule 'ss' , 'sses'
|
179
|
+
rule 'ta' , 'tum'
|
180
|
+
rule 'ia' , 'ium'
|
181
|
+
rule 'ra' , 'rum'
|
182
|
+
rule 'ay' , 'ays'
|
183
|
+
rule 'ey' , 'eys'
|
184
|
+
rule 'oy' , 'oys'
|
185
|
+
rule 'uy' , 'uys'
|
186
|
+
rule 'y' , 'ies'
|
187
|
+
rule 'x' , 'xes'
|
188
|
+
rule 'lf' , 'lves'
|
189
|
+
rule 'us' , 'uses'
|
190
|
+
rule '' , 's'
|
191
|
+
|
192
|
+
# One-way singular rules.
|
193
|
+
|
194
|
+
singular_rule 'of' , 'ofs' # proof
|
195
|
+
singular_rule 'o' , 'oes' # hero, heroes
|
196
|
+
singular_rule 'f' , 'ves'
|
197
|
+
|
198
|
+
# One-way plural rules.
|
199
|
+
|
200
|
+
plural_rule 'fe' , 'ves' # safe, wife
|
201
|
+
plural_rule 's' , 'ses'
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
class String
|
208
|
+
def singular
|
209
|
+
English::Inflect.singular(self)
|
210
|
+
end
|
211
|
+
alias_method(:singularize, :singular)
|
212
|
+
|
213
|
+
def plural
|
214
|
+
English::Inflect.plural(self)
|
215
|
+
end
|
216
|
+
alias_method(:pluralize, :plural)
|
217
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
# Lazy loads items from array.
|
3
|
+
#
|
4
|
+
# Lazy arrays are backed by Proc returning regular array
|
5
|
+
# on first call retrieving it from @load_with_proc.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# ary = LazyArray.new.load_with { Time.now.to_s.split(/\s/) }
|
10
|
+
#
|
11
|
+
# On first attempt to access <tt>ary</tt> (including <tt>inspect</tt>) it will
|
12
|
+
# evaluate load_with's Proc and update own content with its result:
|
13
|
+
#
|
14
|
+
# ary
|
15
|
+
# # ==> ["Mon", "Mar", "17", "10:35:52", "+0200", "2008"]
|
16
|
+
#
|
17
|
+
class LazyArray < BlankSlate
|
18
|
+
def initialize(*args)
|
19
|
+
@load_with_proc = proc {|v| v}
|
20
|
+
@array = Array.new(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Proc to execute lazy loading
|
24
|
+
def load_with(&block)
|
25
|
+
@load_with_proc = block
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Make it look like array for outer world
|
30
|
+
def class
|
31
|
+
Array
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing sym, *args, &blk
|
35
|
+
if @array.respond_to? sym
|
36
|
+
load!
|
37
|
+
@array.__send__ sym, *args, &blk
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def load!
|
46
|
+
if @load_with_proc
|
47
|
+
@array.clear
|
48
|
+
@array.concat @load_with_proc.call(@array)
|
49
|
+
@load_with_proc = nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
# Lazy loads items from array applying procs on each read and write.
|
3
|
+
#
|
4
|
+
# Example:
|
5
|
+
#
|
6
|
+
# @ary[i] = 10
|
7
|
+
#
|
8
|
+
# applies "unmap proc" to new item value.
|
9
|
+
#
|
10
|
+
# @ary.at(i)
|
11
|
+
#
|
12
|
+
# applies "map proc" to value just have been read.
|
13
|
+
#
|
14
|
+
# StrokeDB uses this class to "follow" links to other documents
|
15
|
+
# found in slots in a lazy manner.
|
16
|
+
#
|
17
|
+
# player:
|
18
|
+
# model: [@#8b195509-f9c4-4fea-90c9-425b38bdda3e.ea5eda78-d410-44be-8b14-f4e33f6fa047]
|
19
|
+
# generation: 4
|
20
|
+
#
|
21
|
+
# when model collection item is fetched, reference followed and turned into document
|
22
|
+
# instance with mapping proc of lazy mapping array.
|
23
|
+
class LazyMappingArray < BlankSlate(Array)
|
24
|
+
def initialize(*args)
|
25
|
+
@map_proc = proc {|v| v}
|
26
|
+
@unmap_proc = proc {|v| v}
|
27
|
+
super(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def map_with(&block)
|
31
|
+
@map_proc = block
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def unmap_with(&block)
|
36
|
+
@unmap_proc = block
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def class
|
41
|
+
Array
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing sym, *args, &blk
|
45
|
+
super if sym.to_s =~ /^__/
|
46
|
+
mname = "__#{::BlankSlate::MethodMapping[sym.to_s] || sym}"
|
47
|
+
|
48
|
+
case sym
|
49
|
+
when :push, :unshift, :<<, :[]=, :index, :-
|
50
|
+
last = args.pop
|
51
|
+
last = last.is_a?(Array) ? last.map{|v| @unmap_proc.call(v) } : @unmap_proc.call(last)
|
52
|
+
args.push last
|
53
|
+
|
54
|
+
__send__(mname, *args, &blk)
|
55
|
+
|
56
|
+
when :[], :slice, :at, :map, :shift, :pop, :include?, :last, :first, :zip, :each, :inject, :each_with_index
|
57
|
+
__map{|v| @map_proc.call(v) }.__send__(sym, *args, &blk)
|
58
|
+
|
59
|
+
else
|
60
|
+
__send__(mname, *args, &blk)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
class LazyMappingHash < BlankSlate(Hash)
|
3
|
+
def initialize(original = {}, decoder = nil, encoder = nil)
|
4
|
+
@decoder = decoder || proc {|v| v}
|
5
|
+
@encoder = encoder || proc {|v| v}
|
6
|
+
super(default)
|
7
|
+
original.each {|k,v| self.__squarebracket_set(k,v) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def map_with(&block)
|
11
|
+
@encoder = block
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def unmap_with(&block)
|
16
|
+
@decoder = block
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def class
|
21
|
+
Hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing sym, *args, &blk
|
25
|
+
super if sym.to_s =~ /^__/
|
26
|
+
mname = "__#{::BlankSlate::MethodMapping[sym.to_s] || sym}"
|
27
|
+
|
28
|
+
case sym
|
29
|
+
when :keys, :values
|
30
|
+
__send__(mname, *args, &blk).map{|v| @encoder.call(v) }
|
31
|
+
|
32
|
+
when :each
|
33
|
+
self.__each do |k,v|
|
34
|
+
yield @encoder.call(k), @encoder.call(v)
|
35
|
+
end
|
36
|
+
|
37
|
+
when :[], :[]=
|
38
|
+
args.map!{|v| @decoder.call(v) }
|
39
|
+
@encoder.call __send__(mname, *args, &blk)
|
40
|
+
|
41
|
+
else
|
42
|
+
__send__(mname, *args, &blk)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
module JsonSerializationMethod
|
3
|
+
def serialize(x)
|
4
|
+
x.to_json
|
5
|
+
end
|
6
|
+
def deserialize(x)
|
7
|
+
JSON.parse(x)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module MarshalSerializationMethod
|
12
|
+
def serialize(x)
|
13
|
+
x = x.to_raw if x.respond_to?(:to_raw)
|
14
|
+
Marshal.dump(x)
|
15
|
+
end
|
16
|
+
def deserialize(x)
|
17
|
+
Marshal.load(x)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def self.serialization_method=(method_name)
|
23
|
+
StrokeDB.extend StrokeDB.const_get("#{method_name.to_s.camelize}SerializationMethod")
|
24
|
+
end
|
25
|
+
|
26
|
+
self.serialization_method = :marshal
|
27
|
+
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Enumerable
|
2
|
+
class TriggerPartitionContext
|
3
|
+
def initialize(enum, &block)
|
4
|
+
@enum = enum
|
5
|
+
@cont = block
|
6
|
+
end
|
7
|
+
def fill(&block)
|
8
|
+
@fill = block
|
9
|
+
self
|
10
|
+
end
|
11
|
+
def emit
|
12
|
+
partitions = []
|
13
|
+
cont = @cont
|
14
|
+
fill = @fill
|
15
|
+
p = @enum.inject(nil) do |part, elem|
|
16
|
+
if part && cont.call(part, elem)
|
17
|
+
fill.call(part, elem)
|
18
|
+
part
|
19
|
+
else
|
20
|
+
partitions << part if part
|
21
|
+
yield(elem)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
partitions << p if p
|
25
|
+
partitions
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def trigger_partition(&block)
|
29
|
+
TriggerPartitionContext.new(self, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
class TriggerPartitions
|
33
|
+
def self.partition(list)
|
34
|
+
partitions = []
|
35
|
+
p = list.inject(nil) do |part, elem|
|
36
|
+
if part && continue?(part, elem)
|
37
|
+
fill(part, elem)
|
38
|
+
part
|
39
|
+
else
|
40
|
+
partitions << part if part
|
41
|
+
emit(elem)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
partitions << p if p
|
45
|
+
partitions
|
46
|
+
end
|
47
|
+
def self.continue?(p, e)
|
48
|
+
true
|
49
|
+
end
|
50
|
+
def self.emit(e)
|
51
|
+
[e]
|
52
|
+
end
|
53
|
+
def self.fill(p, e)
|
54
|
+
p << e
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if __FILE__ == $0
|
60
|
+
arr = [1,2,3,4,5, -1, -4, -3, 5, 6, 7, 8, -6, -7]
|
61
|
+
parr = arr.trigger_partition do |partition, element|
|
62
|
+
partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0
|
63
|
+
end.fill do |p, e|
|
64
|
+
p << e
|
65
|
+
end.emit do |e|
|
66
|
+
[e]
|
67
|
+
end
|
68
|
+
|
69
|
+
p arr
|
70
|
+
p parr
|
71
|
+
|
72
|
+
# Class might be faster
|
73
|
+
class SignPartitions < Enumerable::TriggerPartitions
|
74
|
+
def self.continue?(partition, element)
|
75
|
+
partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
p Enumerable::TriggerPartitions.partition(arr)
|
80
|
+
p SignPartitions.partition(arr)
|
81
|
+
|
82
|
+
require 'benchmark'
|
83
|
+
include Benchmark
|
84
|
+
n = 1000
|
85
|
+
bm(32) do |x|
|
86
|
+
x.report("#{n} times:" ) do
|
87
|
+
n.times do
|
88
|
+
arr.trigger_partition do |partition, element|
|
89
|
+
partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0
|
90
|
+
end.fill do |p, e|
|
91
|
+
p << e
|
92
|
+
end.emit do |e|
|
93
|
+
[e]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
arrL = arr*28
|
98
|
+
x.report("#{n} times (x28 larger data):" ) do
|
99
|
+
n.times do
|
100
|
+
arrL.trigger_partition do |partition, element|
|
101
|
+
partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0
|
102
|
+
end.fill do |p, e|
|
103
|
+
p << e
|
104
|
+
end.emit do |e|
|
105
|
+
[e]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
# 35% faster
|
110
|
+
x.report("#{n} times (SignPartitions):" ) do
|
111
|
+
(n/5).times do
|
112
|
+
SignPartitions.partition(arrL)
|
113
|
+
SignPartitions.partition(arrL)
|
114
|
+
SignPartitions.partition(arrL)
|
115
|
+
SignPartitions.partition(arrL)
|
116
|
+
SignPartitions.partition(arrL)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
# + 17% faster (relative to SignPartitions)
|
120
|
+
x.report("#{n} times (raw code):" ) do
|
121
|
+
n.times do
|
122
|
+
parts = []
|
123
|
+
p = arrL.inject(nil) do |partition, element|
|
124
|
+
if partition && (partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0)
|
125
|
+
partition << element
|
126
|
+
partition
|
127
|
+
else
|
128
|
+
parts << partition if partition
|
129
|
+
[element]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
parts << p if p
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/util/util.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
module Util
|
3
|
+
|
4
|
+
class ::Object
|
5
|
+
# Uses references to documents (compared to to_raw using hashes instead)
|
6
|
+
def to_optimized_raw
|
7
|
+
case self
|
8
|
+
when Array
|
9
|
+
map{|v| v.to_optimized_raw }
|
10
|
+
when Hash
|
11
|
+
new_hash = {}
|
12
|
+
each_pair{|k,v| new_hash[k.to_optimized_raw] = v.to_optimized_raw}
|
13
|
+
new_hash
|
14
|
+
else
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
unless RUBY_PLATFORM =~ /java/
|
21
|
+
require 'uuidtools'
|
22
|
+
def self.random_uuid
|
23
|
+
::UUID.random_create.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class CircularReferenceCondition < Exception ; end
|
28
|
+
class << self
|
29
|
+
def catch_circular_reference(value,name = 'StrokeDB.reference_stack')
|
30
|
+
stack = Thread.current[name] ||= []
|
31
|
+
raise CircularReferenceCondition if stack.find{|v| value == v}
|
32
|
+
stack << value
|
33
|
+
yield
|
34
|
+
stack.pop
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/util/xml.rb
ADDED
data/lib/view/view.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
View = Meta.new(:uuid => VIEW_UUID) do
|
3
|
+
attr_accessor :map_with_proc
|
4
|
+
attr_reader :reduce_with_proc
|
5
|
+
|
6
|
+
on_initialization do |view|
|
7
|
+
view.map_with_proc = proc {|doc, *args| doc }
|
8
|
+
end
|
9
|
+
|
10
|
+
def reduce_with(&block)
|
11
|
+
@reduce_with_proc = block
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def map_with(&block)
|
16
|
+
@map_with_proc = block
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def emit(*args)
|
21
|
+
ViewCut.new(store, :view => self, :args => args, :timestamp_state => LTS.zero.counter).emit
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
ViewCut = Meta.new(:uuid => VIEWCUT_UUID) do
|
26
|
+
|
27
|
+
on_new_document do |cut|
|
28
|
+
cut.instance_eval do
|
29
|
+
if view.is_a?(View)
|
30
|
+
@map_with_proc = view.map_with_proc
|
31
|
+
@reduce_with_proc = view.reduce_with_proc
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
before_save do |cut|
|
37
|
+
view = cut.view
|
38
|
+
view.last_cut = cut if view[:last_cut].nil? or (cut[:previous] && view.last_cut == cut.previous)
|
39
|
+
view.save!
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def emit
|
44
|
+
mapped = []
|
45
|
+
store.each(:after_timestamp => timestamp_state, :include_versions => view[:include_versions]) do |doc|
|
46
|
+
mapped << @map_with_proc.call(doc,*args)
|
47
|
+
end
|
48
|
+
documents = (@reduce_with_proc ? mapped.select {|doc| @reduce_with_proc.call(doc,*args) } : mapped).map{|d| d.is_a?(Document) ? d.extend(VersionedDocument) : d}
|
49
|
+
ViewCut.new(store, :documents => documents, :view => view, :args => args, :timestamp_state => store.timestamp.counter, :previous => timestamp_state == 0 ? nil : self)
|
50
|
+
end
|
51
|
+
def to_a
|
52
|
+
documents
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|