strokedb 0.0.2.1 → 0.0.2.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.
Files changed (192) hide show
  1. data/README +18 -20
  2. data/bench.html +4001 -0
  3. data/bin/strokedb +14 -0
  4. data/examples/movies.rb +105 -0
  5. data/examples/movies2.rb +97 -0
  6. data/examples/strokewiki/README +28 -0
  7. data/examples/strokewiki/view/edit.xhtml +27 -0
  8. data/examples/strokewiki/view/new.xhtml +26 -0
  9. data/examples/strokewiki/view/pages.xhtml +27 -0
  10. data/examples/strokewiki/view/show.xhtml +40 -0
  11. data/examples/strokewiki/view/versions.xhtml +25 -0
  12. data/examples/strokewiki/wiki.rb +106 -0
  13. data/examples/todo.rb +92 -0
  14. data/lib/strokedb.rb +85 -0
  15. data/lib/{config → strokedb}/config.rb +14 -9
  16. data/lib/strokedb/console.rb +87 -0
  17. data/lib/strokedb/core_ext.rb +10 -0
  18. data/lib/{util/ext → strokedb/core_ext}/blank.rb +1 -1
  19. data/lib/{util/ext → strokedb/core_ext}/enumerable.rb +0 -0
  20. data/lib/{util/ext → strokedb/core_ext}/fixnum.rb +0 -0
  21. data/lib/strokedb/core_ext/float.rb +4 -0
  22. data/lib/{util/ext → strokedb/core_ext}/hash.rb +0 -0
  23. data/lib/strokedb/core_ext/infinity.rb +33 -0
  24. data/lib/strokedb/core_ext/kernel.rb +41 -0
  25. data/lib/strokedb/core_ext/object.rb +16 -0
  26. data/lib/{util/ext → strokedb/core_ext}/string.rb +28 -1
  27. data/lib/strokedb/core_ext/symbol.rb +13 -0
  28. data/lib/strokedb/data_structures.rb +5 -0
  29. data/lib/strokedb/data_structures/chunked_skiplist.rb +123 -0
  30. data/lib/{data_structures → strokedb/data_structures}/inverted_list.rb +0 -0
  31. data/lib/{data_structures → strokedb/data_structures}/point_query.rb +0 -0
  32. data/lib/strokedb/data_structures/simple_skiplist.rb +350 -0
  33. data/lib/{data_structures → strokedb/data_structures}/skiplist.rb +1 -1
  34. data/lib/{document → strokedb}/document.rb +180 -71
  35. data/lib/{document → strokedb/document}/callback.rb +0 -0
  36. data/lib/{document → strokedb/document}/delete.rb +2 -2
  37. data/lib/strokedb/document/dsl.rb +4 -0
  38. data/lib/{document → strokedb/document/dsl}/associations.rb +0 -0
  39. data/lib/{document → strokedb/document/dsl}/coercions.rb +0 -0
  40. data/lib/strokedb/document/dsl/meta_dsl.rb +7 -0
  41. data/lib/{document → strokedb/document/dsl}/validations.rb +26 -21
  42. data/lib/{document → strokedb/document/dsl}/virtualize.rb +0 -0
  43. data/lib/{document → strokedb/document}/meta.rb +92 -29
  44. data/lib/{document → strokedb/document}/slot.rb +17 -5
  45. data/lib/{document → strokedb/document}/util.rb +0 -0
  46. data/lib/{document → strokedb/document}/versions.rb +2 -2
  47. data/lib/strokedb/index.rb +2 -0
  48. data/lib/strokedb/nsurl.rb +24 -0
  49. data/lib/strokedb/store.rb +149 -0
  50. data/lib/strokedb/stores.rb +6 -0
  51. data/lib/{stores → strokedb/stores}/chainable_storage.rb +20 -14
  52. data/lib/strokedb/stores/file_storage.rb +118 -0
  53. data/lib/{stores/inverted_list_index → strokedb/stores}/inverted_list_file_storage.rb +50 -0
  54. data/lib/strokedb/stores/memory_storage.rb +80 -0
  55. data/lib/{stores → strokedb/stores}/remote_store.rb +10 -4
  56. data/lib/strokedb/sync.rb +4 -0
  57. data/lib/{sync → strokedb/sync}/chain_sync.rb +0 -0
  58. data/lib/{sync → strokedb/sync}/diff.rb +12 -1
  59. data/lib/{sync/stroke_diff → strokedb/sync/diff}/array.rb +1 -1
  60. data/lib/{sync/stroke_diff → strokedb/sync/diff}/default.rb +0 -0
  61. data/lib/{sync/stroke_diff → strokedb/sync/diff}/hash.rb +1 -1
  62. data/lib/{sync/stroke_diff → strokedb/sync/diff}/string.rb +1 -1
  63. data/lib/{sync → strokedb/sync}/lamport_timestamp.rb +0 -0
  64. data/lib/{sync → strokedb/sync}/store_sync.rb +15 -7
  65. data/lib/strokedb/transaction.rb +78 -0
  66. data/lib/{util → strokedb}/util.rb +14 -7
  67. data/lib/strokedb/util/attach_dsl.rb +29 -0
  68. data/lib/{util → strokedb/util}/blankslate.rb +0 -0
  69. data/lib/strokedb/util/class_optimization.rb +93 -0
  70. data/lib/{util → strokedb/util}/inflect.rb +0 -0
  71. data/lib/strokedb/util/java_util.rb +13 -0
  72. data/lib/{util → strokedb/util}/lazy_array.rb +0 -0
  73. data/lib/{util → strokedb/util}/lazy_mapping_array.rb +4 -0
  74. data/lib/{util → strokedb/util}/lazy_mapping_hash.rb +0 -0
  75. data/lib/{util → strokedb/util}/serialization.rb +21 -0
  76. data/lib/strokedb/util/uuid.rb +159 -0
  77. data/lib/{util → strokedb/util}/xml.rb +0 -0
  78. data/lib/{view → strokedb}/view.rb +2 -2
  79. data/lib/strokedb/volumes.rb +5 -0
  80. data/lib/strokedb/volumes/archive_volume.rb +165 -0
  81. data/lib/strokedb/volumes/block_volume.rb +169 -0
  82. data/lib/strokedb/volumes/distributed_pointer.rb +43 -0
  83. data/lib/strokedb/volumes/fixed_length_skiplist_volume.rb +109 -0
  84. data/lib/strokedb/volumes/map_volume.rb +268 -0
  85. data/meta/MANIFEST +175 -0
  86. data/script/console +2 -70
  87. data/spec/integration/remote_store_spec.rb +70 -0
  88. data/spec/integration/search_spec.rb +76 -0
  89. data/spec/integration/spec_helper.rb +1 -0
  90. data/spec/lib/spec_helper.rb +1 -0
  91. data/spec/lib/strokedb/config_spec.rb +250 -0
  92. data/spec/lib/strokedb/core_ext/blank_spec.rb +20 -0
  93. data/spec/lib/strokedb/core_ext/extract_spec.rb +42 -0
  94. data/spec/lib/strokedb/core_ext/float_spec.rb +62 -0
  95. data/spec/lib/strokedb/core_ext/infinity_spec.rb +40 -0
  96. data/spec/lib/strokedb/core_ext/spec_helper.rb +1 -0
  97. data/spec/lib/strokedb/core_ext/string_spec.rb +25 -0
  98. data/spec/lib/strokedb/core_ext/symbol_spec.rb +8 -0
  99. data/spec/lib/strokedb/data_structures/chunked_skiplist_spec.rb +144 -0
  100. data/spec/lib/strokedb/data_structures/inverted_list_spec.rb +172 -0
  101. data/spec/lib/strokedb/data_structures/simple_skiplist_spec.rb +200 -0
  102. data/spec/lib/strokedb/data_structures/skiplist_spec.rb +253 -0
  103. data/spec/lib/strokedb/data_structures/spec_helper.rb +1 -0
  104. data/spec/lib/strokedb/document/associations_spec.rb +319 -0
  105. data/spec/lib/strokedb/document/callbacks_spec.rb +134 -0
  106. data/spec/lib/strokedb/document/coercions_spec.rb +110 -0
  107. data/spec/lib/strokedb/document/document_spec.rb +1063 -0
  108. data/spec/lib/strokedb/document/meta_meta_spec.rb +30 -0
  109. data/spec/lib/strokedb/document/meta_spec.rb +435 -0
  110. data/spec/lib/strokedb/document/metaslot_spec.rb +43 -0
  111. data/spec/lib/strokedb/document/slot_spec.rb +130 -0
  112. data/spec/lib/strokedb/document/spec_helper.rb +1 -0
  113. data/spec/lib/strokedb/document/validations_spec.rb +1081 -0
  114. data/spec/lib/strokedb/document/virtualize_spec.rb +80 -0
  115. data/spec/lib/strokedb/nsurl_spec.rb +73 -0
  116. data/spec/lib/strokedb/spec_helper.rb +1 -0
  117. data/spec/lib/strokedb/stores/chained_storages_spec.rb +116 -0
  118. data/spec/lib/strokedb/stores/spec_helper.rb +1 -0
  119. data/spec/lib/strokedb/stores/store_spec.rb +201 -0
  120. data/spec/lib/strokedb/stores/transaction_spec.rb +107 -0
  121. data/spec/lib/strokedb/sync/chain_sync_spec.rb +43 -0
  122. data/spec/lib/strokedb/sync/diff_spec.rb +111 -0
  123. data/spec/lib/strokedb/sync/lamport_timestamp_spec.rb +174 -0
  124. data/spec/lib/strokedb/sync/slot_diff_spec.rb +164 -0
  125. data/spec/lib/strokedb/sync/spec_helper.rb +1 -0
  126. data/spec/lib/strokedb/sync/store_sync_spec.rb +181 -0
  127. data/spec/lib/strokedb/sync/stroke_diff/array_spec.rb +97 -0
  128. data/spec/lib/strokedb/sync/stroke_diff/complex_spec.rb +58 -0
  129. data/spec/lib/strokedb/sync/stroke_diff/hash_spec.rb +144 -0
  130. data/spec/lib/strokedb/sync/stroke_diff/scalar_spec.rb +23 -0
  131. data/spec/lib/strokedb/sync/stroke_diff/spec_helper.rb +25 -0
  132. data/spec/lib/strokedb/sync/stroke_diff/string_spec.rb +61 -0
  133. data/spec/lib/strokedb/util/attach_dsl_spec.rb +45 -0
  134. data/spec/lib/strokedb/util/inflect_spec.rb +14 -0
  135. data/spec/lib/strokedb/util/lazy_array_spec.rb +157 -0
  136. data/spec/lib/strokedb/util/lazy_mapping_array_spec.rb +174 -0
  137. data/spec/lib/strokedb/util/lazy_mapping_hash_spec.rb +92 -0
  138. data/spec/lib/strokedb/util/spec_helper.rb +1 -0
  139. data/spec/lib/strokedb/util/uuid_spec.rb +46 -0
  140. data/spec/lib/strokedb/view_spec.rb +228 -0
  141. data/spec/lib/strokedb/volumes/archive_volume_spec.rb +105 -0
  142. data/spec/lib/strokedb/volumes/block_volume_spec.rb +100 -0
  143. data/spec/lib/strokedb/volumes/distributed_pointer_spec.rb +14 -0
  144. data/spec/lib/strokedb/volumes/fixed_length_skiplist_volume_spec.rb +177 -0
  145. data/spec/lib/strokedb/volumes/map_volume_spec.rb +172 -0
  146. data/spec/lib/strokedb/volumes/spec_helper.rb +1 -0
  147. data/spec/regression/docref_spec.rb +94 -0
  148. data/spec/regression/meta_spec.rb +23 -0
  149. data/spec/regression/spec_helper.rb +1 -0
  150. data/spec/regression/sync_spec.rb +36 -0
  151. data/spec/spec.opts +7 -0
  152. data/spec/spec_helper.rb +37 -0
  153. data/spec/temp/storages/TIMESTAMP +1 -0
  154. data/spec/temp/storages/UUID +1 -0
  155. data/spec/temp/storages/database-sync/TIMESTAMP +1 -0
  156. data/spec/temp/storages/database-sync/UUID +1 -0
  157. data/spec/temp/storages/database-sync/config +1 -0
  158. data/spec/temp/storages/database-sync/file/LAST +1 -0
  159. data/spec/temp/storages/database-sync/file/bd/f6/bdf675e5-8a7b-494e-97f2-f74a14ccd95d.av +0 -0
  160. data/spec/temp/storages/database-sync/file/uindex.wal +0 -0
  161. data/spec/temp/storages/database-sync/inverted_list_file/INVERTED_INDEX +1 -0
  162. data/spec/temp/storages/inverted_list_storage/INVERTED_INDEX +0 -0
  163. data/strokedb.gemspec +120 -0
  164. data/task/benchmark.task +9 -0
  165. data/task/ditz.task +30 -0
  166. data/task/echoe.rb +17 -0
  167. data/task/rcov.task +50 -0
  168. data/task/rdoc.task +10 -0
  169. data/task/rspec.task +0 -0
  170. data/vendor/java_inline.rb +106 -0
  171. data/vendor/rbmodexcl/mrimodexcl.rb +82 -0
  172. data/vendor/rbmodexcl/rbmodexcl.rb +5 -0
  173. data/vendor/rbmodexcl/rbxmodexcl.rb +48 -0
  174. data/vendor/rbmodexcl/spec/unextend_spec.rb +50 -0
  175. data/vendor/rbmodexcl/spec/uninclude_spec.rb +26 -0
  176. metadata +271 -79
  177. data/CONTRIBUTORS +0 -7
  178. data/CREDITS +0 -13
  179. data/bin/sdbc +0 -2
  180. data/lib/init.rb +0 -57
  181. data/lib/stores/inverted_list_index/inverted_list_index.rb +0 -49
  182. data/lib/stores/skiplist_store/chunk.rb +0 -119
  183. data/lib/stores/skiplist_store/chunk_storage.rb +0 -21
  184. data/lib/stores/skiplist_store/file_chunk_storage.rb +0 -44
  185. data/lib/stores/skiplist_store/memory_chunk_storage.rb +0 -37
  186. data/lib/stores/skiplist_store/skiplist_store.rb +0 -217
  187. data/lib/stores/store.rb +0 -5
  188. data/lib/sync/stroke_diff/stroke_diff.rb +0 -9
  189. data/lib/util/ext/object.rb +0 -8
  190. data/lib/util/java_util.rb +0 -9
  191. data/lib/util/trigger_partition.rb +0 -136
  192. data/strokedb.rb +0 -75
@@ -3,7 +3,7 @@ module StrokeDB
3
3
  class DocumentDeletionError < StandardError
4
4
  end
5
5
 
6
- DeletedDocument = Meta.new(:uuid => DELETED_DOCUMENT_UUID) do
6
+ DeletedDocument = Meta.new do
7
7
  on_load do |doc|
8
8
  doc.make_immutable!
9
9
  end
@@ -11,7 +11,7 @@ module StrokeDB
11
11
  def undelete!
12
12
  deleted_version = versions.previous
13
13
  store.save_as_head!(deleted_version)
14
- self.class.find(uuid)
14
+ store.find(uuid)
15
15
  end
16
16
  end
17
17
 
@@ -0,0 +1,4 @@
1
+ require 'document/dsl/validations'
2
+ require 'document/dsl/virtualize'
3
+ require 'document/dsl/associations'
4
+ require 'document/dsl/coercions'
@@ -0,0 +1,7 @@
1
+ module StrokeDB
2
+ module MetaDSL
3
+ def on_initialize(&block)
4
+ store_dsl_options("on_initialize", block)
5
+ end
6
+ end
7
+ end
@@ -15,6 +15,8 @@ module StrokeDB
15
15
  :too_short => '#{slotname} is too short (minimum is %d characters)',
16
16
  :too_long => '#{slotname} is too long (maximum is %d characters)',
17
17
  :invalid => '#{slotname} is invalid',
18
+ :must_be_integer => '#{slotname} must be integer',
19
+ :not_a_number => '#{slotname} is not a number',
18
20
  }.freeze unless defined? ERROR_MESSAGES
19
21
 
20
22
  # Validates that the specified slot exists in the document. Happens by default on save. Example:
@@ -541,13 +543,13 @@ module StrokeDB
541
543
  end
542
544
 
543
545
  NUMERICALITY_ERRORS = {
544
- 'greater_than' => '#{slotname} must be greater than %d',
546
+ 'greater_than' => '#{slotname} must be greater than %d',
545
547
  'greater_than_or_equal_to' => '#{slotname} must be greater than or equal to %d',
546
- 'equal_to' => '#{slotname} must be equal to %d',
547
- 'less_than' => '#{slotname} must be less than %d',
548
- 'less_than_or_equal_to' => '#{slotname} must be less than or equal to %d',
549
- 'odd' => '#{slotname} must be odd',
550
- 'even' => '#{slotname} must be even'
548
+ 'equal_to' => '#{slotname} must be equal to %d',
549
+ 'less_than' => '#{slotname} must be less than %d',
550
+ 'less_than_or_equal_to' => '#{slotname} must be less than or equal to %d',
551
+ 'odd' => '#{slotname} must be odd',
552
+ 'even' => '#{slotname} must be even',
551
553
  }.freeze unless defined? NUMERICALITY_ERRORS
552
554
 
553
555
  def initialize_validations
@@ -572,23 +574,23 @@ module StrokeDB
572
574
  end
573
575
 
574
576
  install_validations_for(:validates_uniqueness_of) do |doc, validation, slotname|
575
- meta = Kernel.const_get(doc.meta.name)
576
-
577
- !(found = meta.find(slotname.to_sym => doc[slotname])) ||
578
- (found.size == 0) ||
579
- (found.first.uuid == doc.uuid)
577
+ not doc.metas.detect do |meta|
578
+ found = Kernel.const_get(meta.name).find(slotname.to_sym => doc[slotname]) unless meta.name == 'StrokeDB::DeletedDocument'
579
+
580
+ found && found.detect { |item| item.uuid != doc.uuid }
581
+ end
580
582
  end
581
-
583
+
582
584
  # using lambda here enables us to use return
583
585
  numericality = lambda do |doc, validation, slotname|
584
586
  value = doc[slotname]
585
587
 
586
588
  if validation[:only_integer]
587
- return (validation[:message] || "#{slotname} must be integer") unless value.to_s =~ /\A[+-]?\d+\Z/
589
+ return (validation[:message] || :must_be_integer) unless value.to_s =~ /\A[+-]?\d+\Z/
588
590
  value = value.to_i
589
591
  else
590
592
  value = Kernel.Float(value) rescue false
591
- return (validation[:message] || "#{slotname} is not a number") unless value
593
+ return (validation[:message] || :not_a_number) unless value
592
594
  end
593
595
 
594
596
  errors = []
@@ -680,15 +682,18 @@ module StrokeDB
680
682
  next if validation[:allow_nil] && value.nil?
681
683
  next if validation[:allow_blank] && value.blank?
682
684
 
685
+ msg = nil
686
+
683
687
  case validation_result = block.call(doc, validation, slotname_to_validate)
684
- when true then next
685
- when false
686
- add_error(doc, validation, slotname_to_validate, validation[:message])
687
- when String
688
- add_error(doc, validation, slotname_to_validate, validation_result)
689
- when Array
688
+ when true then next
689
+ when false then msg = validation[:message]
690
+ when Symbol then msg = ERROR_MESSAGES[validation_result]
691
+ when String then msg = validation_result
692
+ when Enumerable
690
693
  validation_result.each { |message| add_error(doc, validation, slotname_to_validate, message) }
691
694
  end
695
+
696
+ add_error(doc, validation, slotname_to_validate, msg) if msg
692
697
  end
693
698
  end
694
699
  end
@@ -701,4 +706,4 @@ module StrokeDB
701
706
  doc.errors.add(slotname, os.instance_eval("\"#{message}\""))
702
707
  end
703
708
  end
704
- end
709
+ end
@@ -1,4 +1,7 @@
1
1
  module StrokeDB
2
+
3
+ META_CACHE = {}
4
+
2
5
  # Meta is basically a type. Imagine the following document:
3
6
  #
4
7
  # some_apple:
@@ -20,8 +23,21 @@ module StrokeDB
20
23
  #
21
24
  # Document class will be extended by modules Fruit and Product.
22
25
  module Meta
23
-
26
+
24
27
  class << self
28
+
29
+ def resolve_uuid_name(nsurl,name)
30
+ "meta:#{nsurl}##{name}"
31
+ end
32
+
33
+ def make_uuid_from_fullname(full_name)
34
+ ::StrokeDB::Util.sha1_uuid(full_name)
35
+ end
36
+
37
+ def make_uuid(nsurl, name)
38
+ ::StrokeDB::Util.sha1_uuid("meta:#{nsurl}##{name}")
39
+ end
40
+
25
41
  def new(*args, &block)
26
42
  mod = Module.new
27
43
  args = args.unshift(nil) if args.empty? || args.first.is_a?(Hash)
@@ -44,32 +60,43 @@ module StrokeDB
44
60
  initialize_coercions
45
61
  initialize_virtualizations
46
62
  end
47
- if meta_name = extract_meta_name(*args)
48
- Object.const_set(meta_name, mod)
63
+ if name = args.last.stringify_keys['name']
64
+ META_CACHE[make_uuid(args.last.stringify_keys['nsurl'],args.last.stringify_keys['name'])] = mod
65
+ mod.instance_eval %{
66
+ def name
67
+ '#{name}'
68
+ end
69
+ }
49
70
  end
50
71
  mod
51
72
  end
52
73
 
53
74
  def document(store=nil)
54
75
  raise NoDefaultStoreError.new unless store ||= StrokeDB.default_store
55
- unless meta_doc = store.find(NIL_UUID)
56
- meta_doc = Document.create!(store, :name => Meta.name, :uuid => NIL_UUID)
76
+ unless meta_doc = store.find(uuid)
77
+ meta_doc = Document.create!(store, :name => Meta.name.demodulize, :uuid => uuid, :nsurl => StrokeDB.nsurl)
57
78
  end
58
79
  meta_doc
59
80
  end
81
+
60
82
 
61
83
  private
62
84
 
63
- def extract_meta_name(*args)
64
- if args.first.is_a?(Hash)
65
- args.first[:name]
66
- else
67
- args[1][:name] unless args.empty?
68
- end
85
+ def uuid
86
+ @uuid ||= ::StrokeDB::Util.sha1_uuid("meta:#{StrokeDB.nsurl}##{Meta.name.demodulize}")
69
87
  end
70
88
 
71
89
  end
72
90
 
91
+ def implements(another_meta)
92
+ values = @args.find{|a| a.is_a?(Hash) }
93
+ values.merge!(another_meta.document.to_raw.delete_if {|k,v| ['name','uuid','version','previous_version','meta'].member?(k) })
94
+ values[:implements_metas] ||= []
95
+ values[:implements_metas] << another_meta.document
96
+ include(another_meta)
97
+ self
98
+ end
99
+
73
100
  def +(meta)
74
101
  if is_a?(Module) && meta.is_a?(Module)
75
102
  new_meta = Module.new
@@ -81,9 +108,10 @@ module StrokeDB
81
108
  new_meta.module_eval do
82
109
  extend Meta
83
110
  end
84
- new_meta_name = new_meta.instance_variable_get(:@metas).map{|m| m.name}.join('__')
85
- Object.send(:remove_const, new_meta_name) rescue nil
86
- Object.const_set(new_meta_name, new_meta)
111
+ new_meta_name = new_meta.instance_variable_get(:@metas).map{|m| m.name.demodulize}.join('__')
112
+ mod = self.name.modulize.constantize rescue Object
113
+ mod.send(:remove_const, new_meta_name) rescue nil
114
+ mod.const_set(new_meta_name, new_meta)
87
115
  new_meta
88
116
  elsif is_a?(Document) && meta.is_a?(Document)
89
117
  (Document.new(store, self.to_raw.except('uuid','version','previous_version'), true) +
@@ -92,9 +120,30 @@ module StrokeDB
92
120
  raise "Can't + #{self.class} and #{meta.class}"
93
121
  end
94
122
  end
123
+
124
+ def named(*args,&block)
125
+ args.unshift StrokeDB.default_store unless args.first.is_a?(StrokeDB::Store)
126
+ args << {} unless args.last.is_a?(Hash)
127
+ raise ArgumentError, "you should specify name" unless args[1].is_a?(String)
128
+ name = args[1]
129
+ uuid = ::StrokeDB::Util.sha1_uuid("#{document.uuid}:#{name}")
130
+ unless doc = find(args[0],uuid,&block)
131
+ doc = create!(args[0],args.last.reverse_merge(:uuid => uuid),&block)
132
+ else
133
+ doc.update_slots!(args.last)
134
+ end
135
+ doc
136
+ end
95
137
 
96
- CALLBACKS = %w(on_initialization on_load before_save after_save when_slot_not_found on_new_document on_validation
97
- after_validation on_set_slot)
138
+ CALLBACKS = %w(on_initialization
139
+ on_load
140
+ before_save
141
+ after_save
142
+ when_slot_not_found
143
+ on_new_document
144
+ on_validation
145
+ after_validation
146
+ on_set_slot)
98
147
 
99
148
  CALLBACKS.each do |callback_name|
100
149
  module_eval %{
@@ -143,7 +192,7 @@ module StrokeDB
143
192
  # all_my_joes = User.find(my_store, :name => "joe")
144
193
  # oh_my = User.find(my_store, "1e3d02cc-0769-4bd8-9113-e033b246b013")
145
194
  #
146
- def find(*args)
195
+ def find(*args, &block)
147
196
  if args.empty? || !args.first.respond_to?(:search)
148
197
  raise NoDefaultStoreError unless StrokeDB.default_store
149
198
 
@@ -160,8 +209,7 @@ module StrokeDB
160
209
  case args[1]
161
210
  when String
162
211
  raise ArgumentError, "Invalid UUID" unless args[1].match(UUID_RE)
163
-
164
- store.search(opt.merge({ :uuid => args[1] })).first
212
+ store.find(args[1], &block)
165
213
  when Hash
166
214
  store.search opt.merge(args[1])
167
215
  when nil
@@ -172,14 +220,19 @@ module StrokeDB
172
220
  end
173
221
 
174
222
  #
175
- # Similar to +find+, but a creates document with appropriate slot values if
176
- # not found.
223
+ # Convenience alias for Meta#find.
224
+ #
225
+ alias :all :find
226
+
227
+ #
228
+ # Similar to +find+, but creates a document with an appropriate
229
+ # slot values if document was not found.
177
230
  #
178
231
  # If found, returned is only the first result.
179
232
  #
180
- def find_or_create(*args)
233
+ def find_or_create(*args, &block)
181
234
  result = find(*args)
182
- result.empty? ? create!(*args) : result.first
235
+ result.empty? ? create!(*args, &block) : result.first
183
236
  end
184
237
 
185
238
  def inspect
@@ -200,15 +253,28 @@ module StrokeDB
200
253
  metadocs.size > 1 ? metadocs.inject { |a, b| a + b }.make_immutable! : metadocs.first
201
254
  end
202
255
 
256
+
257
+
258
+ def extended(obj)
259
+ setup_callbacks(obj) if obj.is_a?(Document)
260
+ end
261
+
262
+
203
263
  private
204
-
264
+
205
265
  def make_document(store=nil)
206
266
  raise NoDefaultStoreError.new unless store ||= StrokeDB.default_store
207
267
  @meta_initialization_procs.each {|proc| proc.call }.clear
208
268
 
209
- values = @args.clone.select{|a| Hash === a}.first
269
+ values = @args.clone.select{|a| a.is_a?(Hash) }.first
210
270
  values[:meta] = Meta.document(store)
211
- values[:name] ||= name
271
+ values[:name] ||= name.demodulize
272
+
273
+ raise ArgumentError, "meta can't be nameless" if values[:name].blank?
274
+
275
+ values[:nsurl] ||= name.modulize.empty? ? Module.nsurl : name.modulize.constantize.nsurl
276
+ values[:uuid] ||= Meta.make_uuid(values[:nsurl],values[:name])
277
+
212
278
 
213
279
  if meta_doc = find_meta_doc(values, store)
214
280
  values[:version] = meta_doc.version
@@ -218,7 +284,6 @@ module StrokeDB
218
284
  else
219
285
  args = [store, values]
220
286
  meta_doc = Document.new(*args)
221
- meta_doc.extend(Meta)
222
287
  meta_doc.save!
223
288
  end
224
289
  meta_doc
@@ -227,8 +292,6 @@ module StrokeDB
227
292
  def find_meta_doc(values, store)
228
293
  if uuid = values[:uuid]
229
294
  store.find(uuid)
230
- else
231
- store.search({ :name => values[:name], :meta => Meta.document(store) }).first
232
295
  end
233
296
  end
234
297
 
@@ -1,3 +1,6 @@
1
+ require 'util/lazy_mapping_hash'
2
+ require 'util/lazy_mapping_array'
3
+
1
4
  module StrokeDB
2
5
  class HashSlotValue < LazyMappingHash
3
6
  def with_modification_callback(&block)
@@ -8,6 +11,7 @@ module StrokeDB
8
11
  super(*args)
9
12
  @modification_callback.call if @modification_callback
10
13
  end
14
+
11
15
  end
12
16
 
13
17
  class ArraySlotValue < LazyMappingArray
@@ -67,6 +71,7 @@ module StrokeDB
67
71
  "#<DocRef #{self[0,5]}..>"
68
72
  end
69
73
  alias :to_raw :str
74
+ alias :to_s :str
70
75
 
71
76
  def ==(v)
72
77
  case v
@@ -84,7 +89,10 @@ module StrokeDB
84
89
 
85
90
  class Slot
86
91
  attr_reader :doc, :value, :name
87
-
92
+
93
+ DUMP_PREFIX = "@!Dump:".freeze
94
+ DUMP_PREFIX_RE = /^#{DUMP_PREFIX}/.freeze
95
+
88
96
  def initialize(doc, name = nil)
89
97
  @doc, @name = doc, name
90
98
  @decoded = {}
@@ -139,11 +147,13 @@ module StrokeDB
139
147
  decode_value(element)
140
148
  end
141
149
  when Range, Regexp
142
- "@!Dump:#{StrokeDB::serialize(v)}"
150
+ DUMP_PREFIX + StrokeDB::serialize(v)
143
151
  when Symbol
144
152
  v.to_s
145
- when Time, String, Numeric, TrueClass, FalseClass, NilClass
153
+ when String, Numeric, TrueClass, FalseClass, NilClass
146
154
  v
155
+ when Time
156
+ v.xmlschema(6)
147
157
  else
148
158
  raise ArgumentError, "#{v.class} is not a valid slot value type"
149
159
  end
@@ -152,8 +162,8 @@ module StrokeDB
152
162
  def decode_value(v)
153
163
  case v
154
164
  when VERSIONREF
155
- DocumentReferenceValue.new(v, doc)
156
- when /^@!Dump:/
165
+ DocumentReferenceValue.new(v.to_s, doc)
166
+ when DUMP_PREFIX_RE
157
167
  StrokeDB::deserialize(v[7, v.length-7])
158
168
  when Array
159
169
  ArraySlotValue.new(v).map_with do |element|
@@ -175,6 +185,8 @@ module StrokeDB
175
185
  end
176
186
  when Symbol
177
187
  v.to_s
188
+ when XMLSCHEMA_TIME_RE
189
+ Time.xmlschema(v).localtime # localtime is for compliance with local time objects
178
190
  else
179
191
  v
180
192
  end
@@ -39,7 +39,7 @@ module StrokeDB
39
39
  # Get first version of document
40
40
  #
41
41
  def first
42
- document.new? ? document.clone.extend(VersionedDocument) : self[all_preceding_versions.last]
42
+ document.new? ? document.clone.extend(VersionedDocument) : self[NIL_UUID]
43
43
  end
44
44
 
45
45
 
@@ -51,7 +51,7 @@ module StrokeDB
51
51
  # Returns <tt>nil</tt> if there is no previous version
52
52
  #
53
53
  def previous
54
- self[document.previous_version]
54
+ document.previous_version ? self[document.previous_version] : nil
55
55
  end
56
56
 
57
57
  #
@@ -0,0 +1,2 @@
1
+ module StrokeDB
2
+ end
@@ -0,0 +1,24 @@
1
+ Module.module_eval do
2
+
3
+ def self.reset_nsurls
4
+ @@nsurls = {}
5
+ ::Module.nsurl ''
6
+ ::StrokeDB.nsurl StrokeDB::STROKEDB_NSURL
7
+ end
8
+ def self.find_by_nsurl(url)
9
+ @@nsurls[url]
10
+ end
11
+
12
+ def nsurl(url = nil)
13
+ return @nsurl unless url
14
+ @@nsurls ||= {}
15
+ mod = @@nsurls[url]
16
+ raise ArgumentError, "nsurl #{url.inspect} is already referenced by #{mod.inspect} module" if mod && mod != self
17
+ @@nsurls.delete(url)
18
+ @@nsurls[url] = self
19
+ @nsurl = url
20
+ end
21
+
22
+ end
23
+
24
+ Module.reset_nsurls