ObjectModel 0.3.0

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 (90) hide show
  1. data/README +849 -0
  2. data/lib/ObjectModel.res/config.yaml +5 -0
  3. data/lib/ObjectModel/AnEntity/BackReferences.rb +113 -0
  4. data/lib/ObjectModel/AnEntity/Bag.rb +129 -0
  5. data/lib/ObjectModel/AnEntity/BagCopy.rb +29 -0
  6. data/lib/ObjectModel/AnEntity/ChildrenBag.rb +10 -0
  7. data/lib/ObjectModel/AnEntity/EntityCopy.rb +38 -0
  8. data/lib/ObjectModel/AnEntity/EntityType.rb +408 -0
  9. data/lib/ObjectModel/AnEntity/ReferencesBag.rb +10 -0
  10. data/lib/ObjectModel/AnEntity/entity_cm.rb +108 -0
  11. data/lib/ObjectModel/Entity.rb +278 -0
  12. data/lib/ObjectModel/Errors/LoadError.rb +3 -0
  13. data/lib/ObjectModel/Errors/NoTransactionError.rb +3 -0
  14. data/lib/ObjectModel/Errors/NotFoundError.rb +2 -0
  15. data/lib/ObjectModel/Errors/OutdatedError.rb +8 -0
  16. data/lib/ObjectModel/Errors/ValidationError.rb +3 -0
  17. data/lib/ObjectModel/Indexes/HashIndex.rb +64 -0
  18. data/lib/ObjectModel/Indexes/IndexStorage.rb +64 -0
  19. data/lib/ObjectModel/Indexes/Manager.rb +72 -0
  20. data/lib/ObjectModel/Metadata.rb +34 -0
  21. data/lib/ObjectModel/Metadata.res/after_event_types.rb +25 -0
  22. data/lib/ObjectModel/Metadata.res/attribute_types_shortcuts.rb +10 -0
  23. data/lib/ObjectModel/Metadata.res/before_event_types.rb +25 -0
  24. data/lib/ObjectModel/Metadata.res/child_types_shortcuts.rb +4 -0
  25. data/lib/ObjectModel/Metadata.res/metadata_checks.rb +9 -0
  26. data/lib/ObjectModel/Metadata.res/reference_types_shortcuts.rb +4 -0
  27. data/lib/ObjectModel/Metadata/DSL.rb +11 -0
  28. data/lib/ObjectModel/Metadata/attribute.rb +56 -0
  29. data/lib/ObjectModel/Metadata/child.rb +50 -0
  30. data/lib/ObjectModel/Metadata/events.rb +109 -0
  31. data/lib/ObjectModel/Metadata/name.rb +20 -0
  32. data/lib/ObjectModel/Metadata/reference.rb +50 -0
  33. data/lib/ObjectModel/Metadata/require.rb +10 -0
  34. data/lib/ObjectModel/Metadata/validate.rb +66 -0
  35. data/lib/ObjectModel/Repository.rb +326 -0
  36. data/lib/ObjectModel/Repository/EventProcessor.rb +58 -0
  37. data/lib/ObjectModel/Repository/ObjectStorage.rb +102 -0
  38. data/lib/ObjectModel/Repository/StreamID.rb +20 -0
  39. data/lib/ObjectModel/Repository/StreamStorage.rb +121 -0
  40. data/lib/ObjectModel/Repository/SystemListener.rb +143 -0
  41. data/lib/ObjectModel/Repository/Transaction.rb +63 -0
  42. data/lib/ObjectModel/Repository/TransactionProcessor.rb +36 -0
  43. data/lib/ObjectModel/Tools/DefaultTransactionStrategy.rb +9 -0
  44. data/lib/ObjectModel/Tools/InMemoryCache.rb +9 -0
  45. data/lib/ObjectModel/Tools/NoCache.rb +18 -0
  46. data/lib/ObjectModel/Tools/OGLRUCache.rb +37 -0
  47. data/lib/ObjectModel/Types/BagType.rb +94 -0
  48. data/lib/ObjectModel/Types/BooleanType.rb +42 -0
  49. data/lib/ObjectModel/Types/ClassType.rb +43 -0
  50. data/lib/ObjectModel/Types/DataType.rb +44 -0
  51. data/lib/ObjectModel/Types/DateType.rb +43 -0
  52. data/lib/ObjectModel/Types/NumberType.rb +62 -0
  53. data/lib/ObjectModel/Types/ObjectType.rb +164 -0
  54. data/lib/ObjectModel/Types/ProcType.rb +43 -0
  55. data/lib/ObjectModel/Types/SingleType.rb +59 -0
  56. data/lib/ObjectModel/Types/StringType.rb +39 -0
  57. data/lib/ObjectModel/_require.rb +43 -0
  58. data/lib/ObjectModel/require.rb +1 -0
  59. data/rakefile +62 -0
  60. data/spec/ObjectModel/BasicSpec/BaseClass.rb +7 -0
  61. data/spec/ObjectModel/BasicSpec/BaseTypes.rb +11 -0
  62. data/spec/ObjectModel/BasicSpec/Descendant.rb +5 -0
  63. data/spec/ObjectModel/BasicSpec/EachTest.rb +14 -0
  64. data/spec/ObjectModel/BasicSpec/UpChild.rb +10 -0
  65. data/spec/ObjectModel/BasicSpec/UpParent.rb +11 -0
  66. data/spec/ObjectModel/ErrorsSpec/AfterCommitError.rb +9 -0
  67. data/spec/ObjectModel/ExtendedSpec/CustomInitialization.rb +11 -0
  68. data/spec/ObjectModel/ExtendedSpec/UpNotNil.rb +8 -0
  69. data/spec/ObjectModel/ExtendedSpec/UpParent.rb +11 -0
  70. data/spec/ObjectModel/ValidationSpec/BaseTypes.rb +11 -0
  71. data/spec/aspect_spec.rb +55 -0
  72. data/spec/back_references_spec.rb +161 -0
  73. data/spec/basic_spec.rb +162 -0
  74. data/spec/cascade_delete_spec.rb +168 -0
  75. data/spec/complex_events_spec.rb +134 -0
  76. data/spec/concurrency_spec.rb +186 -0
  77. data/spec/containment_spec.rb +146 -0
  78. data/spec/data_migration_spec.rb +51 -0
  79. data/spec/errors_spec.rb +65 -0
  80. data/spec/events_spec.rb +173 -0
  81. data/spec/extended_spec.rb +171 -0
  82. data/spec/indexing_spec.rb +56 -0
  83. data/spec/set_in_memory.rb +2 -0
  84. data/spec/set_no_cache.rb +2 -0
  85. data/spec/smoke_test_spec.rb +85 -0
  86. data/spec/stream_spec.rb +143 -0
  87. data/spec/stream_storage.rb +148 -0
  88. data/spec/timer.rb +5 -0
  89. data/spec/validation_spec.rb +87 -0
  90. metadata +186 -0
@@ -0,0 +1,62 @@
1
+ class NumberType
2
+ class << self
3
+ def initial_value m, e
4
+ 0
5
+ # e.instance_variable_set m.ivname, 0
6
+ end
7
+
8
+ def initialize_copy m, e, c
9
+ value_copy = e.instance_variable_get(m.ivname)
10
+ c[m.ivname] = value_copy
11
+ end
12
+
13
+ def write_back c, e, m
14
+ value = c[m.ivname]
15
+ value.should! :be_a, Numeric
16
+ e.instance_variable_set m.ivname, value
17
+ end
18
+
19
+ def persist c, entity_id, m, storage
20
+ value, klass = dump_number c[m.ivname]
21
+ storage[:entities_content].insert(
22
+ :entity_id => entity_id,
23
+ :name => m.name.to_s,
24
+ :value =>value,
25
+ :class => klass
26
+ )
27
+ end
28
+
29
+ def load m, e, storage
30
+ row = storage[:entities_content][:entity_id => e.entity_id, :name => m.name.to_s]
31
+ raise LoadError unless row
32
+ value = load_number row[:value], row[:class]
33
+
34
+ e.instance_variable_set m.ivname, value
35
+ end
36
+
37
+ def validate_type value
38
+ value.is_a? Numeric
39
+ end
40
+
41
+ protected
42
+ def dump_number number
43
+ case number
44
+ when Fixnum then [number.to_s, "NUMBER_F"]
45
+ when Bignum then [number.to_s, "NUMBER_B"]
46
+ when Float then [number.to_s, "NUMBER_FL"]
47
+ else
48
+ should! :be_never_called
49
+ end
50
+ end
51
+
52
+ def load_number value, klass
53
+ case klass
54
+ when "NUMBER_F" then value.to_i
55
+ when "NUMBER_B" then value.to_i
56
+ when "NUMBER_FL" then value.to_f
57
+ else
58
+ raise LoadError
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,164 @@
1
+ class ObjectType
2
+
3
+ class << self
4
+ def initial_value m, e
5
+ nil
6
+ # e.instance_variable_set m.ivname, nil
7
+ end
8
+
9
+ def initialize_storage db
10
+ db.create_table :value_objects do
11
+ column :entity_id, :text
12
+ column :name, :text
13
+ column :yaml, :text
14
+ column :class, :text
15
+ # index :entity_id
16
+ end
17
+ end
18
+
19
+ def initialize_copy m, e, c
20
+ value = e.instance_variable_get(m.ivname)
21
+ value_copy = if value == nil
22
+ nil
23
+ elsif value.respond_to? :copy
24
+ value.copy
25
+ else
26
+ copy_object value
27
+ end
28
+ c[m.ivname] = value_copy
29
+ end
30
+
31
+ def write_back c, e, m
32
+ value = c[m.ivname]
33
+ freeze_all_tree value
34
+ e.instance_variable_set m.ivname, value
35
+ end
36
+
37
+ def persist c, entity_id, m, storage
38
+ storage[:value_objects].filter(:entity_id => entity_id, :name => m.name.to_s).delete
39
+ value, klass = dump_object c[m.ivname]
40
+ storage[:value_objects].insert(
41
+ :entity_id => entity_id,
42
+ :name => m.name.to_s,
43
+ :yaml => value,
44
+ :class => klass
45
+ )
46
+ end
47
+
48
+ def delete e, m, storage
49
+ storage[:value_objects].filter(:entity_id => e.entity_id, :name => m.name.to_s).delete
50
+ end
51
+
52
+ def load m, e, storage
53
+ row = storage[:value_objects][:entity_id => e.entity_id, :name => m.name.to_s]
54
+ raise LoadError unless row
55
+
56
+ value = load_object row[:yaml], row[:class] #YAML.load row[:yaml] # YAML doesn't raise ConstMissing, so we can't just load.
57
+
58
+ freeze_all_tree value
59
+ e.instance_variable_set m.ivname, value
60
+ end
61
+
62
+ def print_storage db, name
63
+ return unless name == nil or name == :value_objects
64
+ puts "\nValueObjects: size = #{db[:value_objects].size}"
65
+ # db[:value_objects].print
66
+ end
67
+
68
+ def validate_type value
69
+ !(value.is_a?(Entity) or value.is_a?(Proc))
70
+ end
71
+
72
+ # Becouse YAML don't raise ConstMissing error we need to preload all Classes from YAML data.
73
+ def yaml_load data
74
+ begin
75
+ doc = YAML.parse data
76
+ load_classes_for doc
77
+ o = doc.transform
78
+
79
+ return o
80
+ rescue Exception => e
81
+ warn e
82
+ raise e
83
+ end
84
+ end
85
+
86
+ protected
87
+ def freeze_all_tree value, processed = Set.new
88
+ value.should_not! :be_a, Entity
89
+ return if value.class == Module or value.class == Class
90
+
91
+ case value
92
+ when String then
93
+ value.freeze
94
+ return
95
+ else
96
+ return if processed.include? value.object_id
97
+ processed << value.object_id
98
+
99
+ value.freeze
100
+ value.instance_variables.each do |ivname|
101
+ iv = value.instance_variable_get ivname
102
+ ObjectType.freeze_all_tree iv, processed
103
+ end
104
+
105
+ if value.respond_to? :each
106
+ value.each do |o|
107
+ ObjectType.freeze_all_tree o, processed
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ def dump_object object
114
+ if object.class == Module or object.class == Class
115
+ return object.name, "CLASS"
116
+ elsif object.is_a? Proc
117
+ return object.to_ruby, "PROC"
118
+ else
119
+ return YAML.dump(object), "YAML"
120
+ end
121
+ end
122
+
123
+ def load_object data, klass
124
+ if klass == "CLASS" or klass == "PROC"
125
+ eval data, TOPLEVEL_BINDING, __FILE__, __LINE__
126
+ elsif klass == "YAML"
127
+ yaml_load data
128
+ else
129
+ should! :never_be_called
130
+ end
131
+ end
132
+
133
+ def copy_object object
134
+ Marshal.load(Marshal.dump(object))
135
+ end
136
+
137
+ PRELOADED_TYPES = %w{hash map array seq}
138
+ def load_classes_for doc, processed = []
139
+ return if !doc or processed.include?(doc)
140
+ processed << doc
141
+
142
+ return unless doc.type_id
143
+
144
+ info = doc.type_id.split(':', 4)
145
+ type, klass = info[2], info[3]
146
+
147
+ if klass and !PRELOADED_TYPES.include?(type)
148
+ eval(klass, TOPLEVEL_BINDING, __FILE__, __LINE__)
149
+ end
150
+
151
+ if doc.value.is_a? Hash
152
+ doc.value.each { |k,v|
153
+ load_classes_for v, processed
154
+ }
155
+ elsif doc.value.is_a? Array
156
+ doc.value.each { |v|
157
+ load_classes_for v, processed
158
+ }
159
+ else
160
+ # raise
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,43 @@
1
+ class ProcType
2
+ class << self
3
+ def initial_value m, e
4
+ nil
5
+ # e.instance_variable_set m.ivname, nil
6
+ end
7
+
8
+ def initialize_copy m, e, c
9
+ value_copy = e.instance_variable_get(m.ivname)
10
+ c[m.ivname] = value_copy
11
+ end
12
+
13
+ def write_back c, e, m
14
+ value = c[m.ivname]
15
+ value.should! :be_a, [NilClass, Proc]
16
+ e.instance_variable_set m.ivname, value
17
+ end
18
+
19
+ def load m, e, storage
20
+ row = storage[:entities_content][:entity_id => e.entity_id, :name => m.name.to_s]
21
+
22
+ raise LoadError unless row and row[:class] == "PROC"
23
+ value = row[:value]
24
+ value = eval(value, TOPLEVEL_BINDING, __FILE__, __LINE__) if value
25
+ e.instance_variable_set m.ivname, value
26
+ end
27
+
28
+ def persist c, entity_id, m, storage
29
+ value = c[m.ivname]
30
+ value = value.to_ruby if value
31
+ storage[:entities_content].insert(
32
+ :entity_id => entity_id,
33
+ :name => m.name.to_s,
34
+ :value => value,
35
+ :class => "PROC"
36
+ )
37
+ end
38
+
39
+ def validate_type value
40
+ value == nil or value.is_a?(Proc)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,59 @@
1
+ class SingleType
2
+ class << self
3
+ inherit Log
4
+
5
+ def initial_value m, e
6
+ nil
7
+ # e.instance_variable_set m.ivname, nil
8
+ end
9
+
10
+ def initialize_copy m, e, c
11
+ c[m.ivname] = e.instance_variable_get(m.ivname)
12
+ end
13
+
14
+ def write_back c, e, m
15
+ value = c[m.ivname]
16
+ value.should! :be_a, [NilClass, String]
17
+ e.instance_variable_set m.ivname, value
18
+ end
19
+
20
+ def load m, e, storage
21
+ row = storage[:entities_content][:entity_id => e.entity_id, :name => m.name.to_s]
22
+ raise LoadError unless row
23
+
24
+ value = AnEntity::EntityType.load_id! row[:value], row[:class]
25
+ e.instance_variable_set m.ivname, value
26
+ end
27
+
28
+ def persist c, entity_id, m, storage
29
+ value, klass = AnEntity::EntityType.dump_id! c[m.ivname]
30
+ storage[:entities_content].insert(
31
+ :entity_id => entity_id,
32
+ :name => m.name.to_s,
33
+ :value => value,
34
+ :class => klass
35
+ )
36
+ end
37
+
38
+ def delete_all_children e, m
39
+ child = e.send m.name
40
+ # p [e.name, m.name, child]
41
+ child.delete if child != nil
42
+ end
43
+
44
+ def delete_all_references_to referrer, e, m
45
+ referrer.send m.name.to_writer, nil if referrer.send(m.name) == e
46
+ end
47
+
48
+ def delete_from_parent e, parent, m
49
+ if parent.send(m.name.to_reader) == e
50
+ parent.send m.name.to_writer, nil
51
+ end
52
+ end
53
+
54
+ def each e, m, &b
55
+ v = e.send m.name
56
+ b.call v if v != nil
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,39 @@
1
+ class StringType
2
+ class << self
3
+ def initial_value m, e
4
+ ""
5
+ # e.instance_variable_set m.ivname, ""
6
+ end
7
+
8
+ def initialize_copy m, e, c
9
+ value_copy = e.instance_variable_get(m.ivname).dup
10
+ c[m.ivname] = value_copy
11
+ end
12
+
13
+ def write_back c, e, m
14
+ value = c[m.ivname]
15
+ value.should! :be_a, String
16
+ e.instance_variable_set m.ivname, value
17
+ end
18
+
19
+ def load m, e, storage
20
+ row = storage[:entities_content][:entity_id => e.entity_id, :name => m.name.to_s]
21
+
22
+ raise LoadError unless row and row[:class] == "STRING"
23
+ e.instance_variable_set m.ivname, row[:value]
24
+ end
25
+
26
+ def persist c, entity_id, m, storage
27
+ storage[:entities_content].insert(
28
+ :entity_id => entity_id,
29
+ :name => m.name.to_s,
30
+ :value => c[m.ivname],
31
+ :class => "STRING"
32
+ )
33
+ end
34
+
35
+ def validate_type value
36
+ value.is_a? String
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ require 'RubyExt/require'
2
+
3
+ require 'sequel'
4
+
5
+ require 'sync'
6
+
7
+ require 'ruby2ruby'
8
+ require 'parse_tree'
9
+ require 'parse_tree_extensions'
10
+
11
+ require 'facets/lrucache'
12
+
13
+ module ObjectModel
14
+ # Config
15
+ user_conf = if File.exist?("config/object_model.yaml")
16
+ YAML.load(File.read("config/object_model.yaml"))
17
+ else
18
+ {}
19
+ end
20
+ CONFIG = RubyExt::Config.new({}, user_conf, ObjectModel["config.yaml"])
21
+
22
+ # Metadata
23
+ require "#{File.dirname(__FILE__)}/Metadata/require"
24
+
25
+ # ObjectStorage Initialization
26
+ [
27
+ AnEntity::BackReferences,
28
+ AnEntity::EntityType,
29
+ Types::BagType,
30
+ Types::ObjectType,
31
+ ].each{|type| Repository::ObjectStorage::TYPES_TO_INITIALIZE << type}
32
+
33
+ # Handy Scope
34
+ NotFoundError = Errors::NotFoundError
35
+ OutdatedError = Errors::OutdatedError
36
+ NoTransactionError = Errors::NoTransactionError
37
+ LoadError = Errors::LoadError
38
+ ValidationError = Errors::ValidationError
39
+ StreamID = Repository::StreamID
40
+ Transaction = Repository::Transaction
41
+ HashIndex = Indexes::HashIndex
42
+ end
43
+
@@ -0,0 +1 @@
1
+ require "ObjectModel/_require"
data/rakefile ADDED
@@ -0,0 +1,62 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ Dir.chdir File.dirname(__FILE__)
5
+
6
+ # Specs
7
+ task :default => :spec
8
+ task :spec => [:spec_no_cache, :spec_in_memory]
9
+
10
+ Spec::Rake::SpecTask.new('spec_no_cache') do |t|
11
+ dir = File.dirname __FILE__
12
+ t.spec_files = ["spec/set_no_cache.rb"] + FileList["spec/**/*_spec.rb"]
13
+ t.libs = ["lib", "spec", "#{File.expand_path "./.."}"]
14
+ end
15
+
16
+ Spec::Rake::SpecTask.new('spec_in_memory') do |t|
17
+ dir = File.dirname __FILE__
18
+ t.spec_files = ["spec/set_in_memory.rb"] + FileList["spec/**/*_spec.rb"]
19
+ t.libs = ["lib", "spec", "#{File.expand_path "./.."}"]
20
+ end
21
+
22
+ # Gem
23
+ require 'rake/clean'
24
+ require 'rake/gempackagetask'
25
+ require 'fileutils'
26
+
27
+ spec = Gem::Specification.new do |s|
28
+ s.name = "ObjectModel"
29
+ s.version = "0.3.0"
30
+ s.summary = "ObjectModel is an Object Oriented Database inspired by MDD approach, db4o and ZODB."
31
+ s.description = "ObjectModel is an Object Oriented Database inspired by MDD approach, db4o and ZODB."
32
+ s.author = "Alexey Petrushin"
33
+ # s.email = ""
34
+ s.homepage = "http://www.bos-tec.com"
35
+ s.rubyforge_project = "ObjectModel"
36
+
37
+ s.platform = Gem::Platform::RUBY
38
+ s.has_rdoc = true
39
+ s.extra_rdoc_files = ["README"]
40
+
41
+ s.files = (%w{rakefile README} + Dir.glob("{lib,spec}/**/*"))\
42
+ .select{|f| f !~ /^\./}
43
+ # s.executables = ['restclient']
44
+
45
+ s.add_dependency "RubyExt"
46
+ s.add_dependency "sequel"
47
+ s.add_dependency "ruby2ruby"
48
+
49
+ s.require_path = "lib"
50
+ end
51
+
52
+ Rake::GemPackageTask.new(spec) do |p|
53
+ package_dir = "#{File.expand_path File.dirname(__FILE__)}/../build"
54
+ # FileUtils.mkdir package_dir unless File.exist? package_dir
55
+ p.need_tar = true if RUBY_PLATFORM !~ /mswin/
56
+ p.need_zip = true
57
+ p.package_dir = package_dir
58
+ end
59
+
60
+ CLEAN.include [ 'pkg', '*.gem']
61
+
62
+ task :release => [:gem, :clean]