maglevrecord 0.0.3 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/.gitignore +35 -0
  2. data/.travis.yml +19 -0
  3. data/Gemfile +13 -0
  4. data/README.md +89 -0
  5. data/Rakefile +22 -0
  6. data/install.sh +238 -0
  7. data/lib/maglev_record/base.rb +10 -62
  8. data/lib/maglev_record/enumerable.rb +13 -24
  9. data/lib/maglev_record/errors.rb +10 -0
  10. data/lib/maglev_record/integration.rb +7 -0
  11. data/lib/maglev_record/maglev_record.rb +13 -0
  12. data/lib/maglev_record/maglev_support/active_support_patch.rb +31 -0
  13. data/lib/maglev_record/maglev_support/concern.rb +19 -0
  14. data/lib/maglev_record/maglev_support/maglev_support.rb +15 -0
  15. data/lib/maglev_record/maglev_support/secure_password.rb +39 -0
  16. data/lib/maglev_record/migration/loader.rb +38 -0
  17. data/lib/maglev_record/migration/migration.rb +142 -0
  18. data/lib/maglev_record/migration/migrator.rb +40 -0
  19. data/lib/maglev_record/migration/operations.rb +92 -0
  20. data/lib/maglev_record/migration.rb +5 -0
  21. data/lib/maglev_record/persistence.rb +23 -48
  22. data/lib/maglev_record/raketasks.rb +9 -0
  23. data/lib/maglev_record/read_write.rb +20 -10
  24. data/lib/maglev_record/rooted_base.rb +8 -0
  25. data/lib/maglev_record/rooted_enumerable.rb +25 -0
  26. data/lib/maglev_record/rooted_persistence.rb +36 -0
  27. data/lib/maglev_record/sensible.rb +28 -0
  28. data/lib/maglev_record/snapshot/change.rb +53 -0
  29. data/lib/maglev_record/snapshot/snapshot.rb +67 -0
  30. data/lib/maglev_record/snapshot/snapshotable.rb +58 -0
  31. data/lib/maglev_record/snapshot.rb +5 -0
  32. data/lib/maglev_record/tools/object_reference.rb +189 -0
  33. data/lib/maglev_record/tools/submodule_finder.rb +42 -0
  34. data/lib/maglev_record/tools.rb +2 -0
  35. data/lib/maglev_record.rb +60 -4
  36. data/lib/tasks/database.rake +38 -0
  37. data/maglevrecord.gemspec +17 -0
  38. data/rails/init.rb +1 -0
  39. data/test/_test_object_reference.rb +70 -0
  40. data/test/example_model.rb +26 -13
  41. data/test/migration/dummy_migrations/migration_1.rb +8 -0
  42. data/test/migration/dummy_migrations/migration_2.rb +8 -0
  43. data/test/migration/dummy_migrations/migration_3.rb +8 -0
  44. data/test/migration/migrations/migration_1.rb +12 -0
  45. data/test/migration/migrations/migration_2.rb +12 -0
  46. data/test/migration/migrations/migration_3.rb +12 -0
  47. data/test/migration/operation_setup.rb +91 -0
  48. data/test/migration/projects/project1/.gitignore +15 -0
  49. data/test/migration/projects/project1/Gemfile +43 -0
  50. data/test/migration/projects/project1/Gemfile.lock +114 -0
  51. data/test/migration/projects/project1/README.rdoc +261 -0
  52. data/test/migration/projects/project1/Rakefile +17 -0
  53. data/test/migration/projects/project1/app/assets/images/rails.png +0 -0
  54. data/test/migration/projects/project1/app/assets/javascripts/application.js +15 -0
  55. data/test/migration/projects/project1/app/assets/stylesheets/application.css +13 -0
  56. data/test/migration/projects/project1/app/controllers/application_controller.rb +3 -0
  57. data/test/migration/projects/project1/app/helpers/application_helper.rb +2 -0
  58. data/test/migration/projects/project1/app/mailers/.gitkeep +0 -0
  59. data/test/migration/projects/project1/app/models/.gitkeep +0 -0
  60. data/test/migration/projects/project1/app/views/layouts/application.html.erb +14 -0
  61. data/test/migration/projects/project1/config/application.rb +62 -0
  62. data/test/migration/projects/project1/config/boot.rb +6 -0
  63. data/test/migration/projects/project1/config/database.yml +25 -0
  64. data/test/migration/projects/project1/config/environment.rb +5 -0
  65. data/test/migration/projects/project1/config/environments/development.rb +37 -0
  66. data/test/migration/projects/project1/config/environments/production.rb +67 -0
  67. data/test/migration/projects/project1/config/initializers/backtrace_silencers.rb +7 -0
  68. data/test/migration/projects/project1/config/initializers/inflections.rb +15 -0
  69. data/test/migration/projects/project1/config/initializers/mime_types.rb +5 -0
  70. data/test/migration/projects/project1/config/initializers/secret_token.rb +7 -0
  71. data/test/migration/projects/project1/config/initializers/session_store.rb +8 -0
  72. data/test/migration/projects/project1/config/initializers/wrap_parameters.rb +14 -0
  73. data/test/migration/projects/project1/config/locales/en.yml +5 -0
  74. data/test/migration/projects/project1/config/routes.rb +58 -0
  75. data/test/migration/projects/project1/config.ru +4 -0
  76. data/test/migration/projects/project1/db/seeds.rb +7 -0
  77. data/test/migration/projects/project1/lib/assets/.gitkeep +0 -0
  78. data/test/migration/projects/project1/lib/tasks/.gitkeep +0 -0
  79. data/test/migration/projects/project1/log/.gitkeep +0 -0
  80. data/test/migration/projects/project1/public/404.html +26 -0
  81. data/test/migration/projects/project1/public/422.html +26 -0
  82. data/test/migration/projects/project1/public/500.html +25 -0
  83. data/test/migration/projects/project1/public/favicon.ico +0 -0
  84. data/test/migration/projects/project1/public/index.html +241 -0
  85. data/test/migration/projects/project1/public/robots.txt +5 -0
  86. data/test/migration/projects/project1/script/rails +6 -0
  87. data/test/migration/projects/project2/.gitignore +15 -0
  88. data/test/migration/projects/project2/Gemfile +44 -0
  89. data/test/migration/projects/project2/Gemfile.lock +115 -0
  90. data/test/migration/projects/project2/README.rdoc +261 -0
  91. data/test/migration/projects/project2/Rakefile +17 -0
  92. data/test/migration/projects/project2/app/assets/images/rails.png +0 -0
  93. data/test/migration/projects/project2/app/assets/javascripts/application.js +15 -0
  94. data/test/migration/projects/project2/app/assets/stylesheets/application.css +13 -0
  95. data/test/migration/projects/project2/app/controllers/application_controller.rb +3 -0
  96. data/test/migration/projects/project2/app/helpers/application_helper.rb +2 -0
  97. data/test/migration/projects/project2/app/mailers/.gitkeep +0 -0
  98. data/test/migration/projects/project2/app/models/.gitkeep +0 -0
  99. data/test/migration/projects/project2/app/models/project_model.rb +8 -0
  100. data/test/migration/projects/project2/app/views/layouts/application.html.erb +14 -0
  101. data/test/migration/projects/project2/config/application.rb +62 -0
  102. data/test/migration/projects/project2/config/boot.rb +6 -0
  103. data/test/migration/projects/project2/config/database.yml +25 -0
  104. data/test/migration/projects/project2/config/environment.rb +5 -0
  105. data/test/migration/projects/project2/config/environments/development.rb +37 -0
  106. data/test/migration/projects/project2/config/environments/production.rb +67 -0
  107. data/test/migration/projects/project2/config/initializers/backtrace_silencers.rb +7 -0
  108. data/test/migration/projects/project2/config/initializers/inflections.rb +15 -0
  109. data/test/migration/projects/project2/config/initializers/mime_types.rb +5 -0
  110. data/test/migration/projects/project2/config/initializers/secret_token.rb +7 -0
  111. data/test/migration/projects/project2/config/initializers/session_store.rb +8 -0
  112. data/test/migration/projects/project2/config/initializers/wrap_parameters.rb +14 -0
  113. data/test/migration/projects/project2/config/locales/en.yml +5 -0
  114. data/test/migration/projects/project2/config/routes.rb +58 -0
  115. data/test/migration/projects/project2/config.ru +4 -0
  116. data/test/migration/projects/project2/db/seeds.rb +7 -0
  117. data/test/migration/projects/project2/lib/assets/.gitkeep +0 -0
  118. data/test/migration/projects/project2/lib/tasks/.gitkeep +0 -0
  119. data/test/migration/projects/project2/log/.gitkeep +0 -0
  120. data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.31.38.rb +16 -0
  121. data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.31.52.rb +16 -0
  122. data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.32.07.rb +16 -0
  123. data/test/migration/projects/project2/public/404.html +26 -0
  124. data/test/migration/projects/project2/public/422.html +26 -0
  125. data/test/migration/projects/project2/public/500.html +25 -0
  126. data/test/migration/projects/project2/public/favicon.ico +0 -0
  127. data/test/migration/projects/project2/public/index.html +241 -0
  128. data/test/migration/projects/project2/public/robots.txt +5 -0
  129. data/test/migration/projects/project2/script/rails +6 -0
  130. data/test/migration/test_loader.rb +78 -0
  131. data/test/migration/test_migration.rb +127 -0
  132. data/test/migration/test_nonexistent_classes.rb +120 -0
  133. data/test/migration/test_operations_fit_together.rb +68 -0
  134. data/test/migration/test_project.rb +105 -0
  135. data/test/migration/test_project1.slow.rb +58 -0
  136. data/test/migration/test_project2.slow.rb +34 -0
  137. data/test/migration/test_remove.rb +219 -0
  138. data/test/migration/test_rename.rb +238 -0
  139. data/test/migration/test_scenario.rb +37 -0
  140. data/test/migration/todo.txt +17 -0
  141. data/test/more_asserts.rb +63 -0
  142. data/test/snapshot/test_snapshot.rb +99 -0
  143. data/test/snapshot/test_snapshot_attributes.slow.rb +57 -0
  144. data/test/snapshot/test_snapshot_classes.slow.rb +32 -0
  145. data/test/snapshot/test_snapshotable.rb +53 -0
  146. data/test/test_accessors.rb +46 -0
  147. data/test/test_active_model_like_interface.rb +1 -1
  148. data/test/test_model_timestamps.rb +22 -0
  149. data/test/test_more_asserts.rb +68 -0
  150. data/test/test_naming.rb +22 -0
  151. data/test/test_persistence.rb +127 -0
  152. data/test/test_query_interface.rb +20 -25
  153. data/test/test_sensibles.rb +38 -0
  154. data/test/test_validation.rb +20 -57
  155. data/todo.txt +1 -0
  156. data/update.sh +180 -0
  157. metadata +156 -12
  158. data/lib/maglev_record/model_not_saved_or_reset.rb +0 -15
  159. data/test/test_dirty_object.rb +0 -50
  160. data/test/test_maglev_record_base.rb +0 -22
  161. data/test/test_maglev_simple_persistance.rb +0 -45
@@ -0,0 +1,67 @@
1
+ require "maglev_record/snapshot/change"
2
+
3
+ module MaglevRecord
4
+ class ClassSnapshot
5
+ def initialize(cls)
6
+ @snapshot_class = cls
7
+ @attr_readers = cls.attr_readers
8
+ @files = cls.file_paths
9
+ @exists = cls.has_definitions?
10
+ end
11
+
12
+ def exists?
13
+ @exists
14
+ end
15
+
16
+ def ==(other)
17
+ self.snapshot_class == other.snapshot_class \
18
+ and self.exists? == other.exists?
19
+ end
20
+
21
+ alias :eql? :==
22
+
23
+ def snapshot_class
24
+ @snapshot_class
25
+ end
26
+
27
+ def changes_since(older)
28
+ return nil unless changed_since?(older)
29
+ ClassChange.new(older, self)
30
+ end
31
+
32
+ def changed_since?(older)
33
+ attr_readers != older.attr_readers
34
+ end
35
+
36
+ def attr_readers
37
+ @attr_readers
38
+ end
39
+
40
+ def class_name
41
+ @snapshot_class.name
42
+ end
43
+ end
44
+
45
+ class Snapshot
46
+
47
+ def for_class(cls)
48
+ ClassSnapshot.new(cls)
49
+ end
50
+
51
+ def initialize
52
+ @class_snapshots = Snapshotable.snapshotable_classes.map{ |cls|
53
+ for_class cls
54
+ }
55
+ end
56
+
57
+ def changes_since(older)
58
+ Change.new(older, self)
59
+ end
60
+
61
+ def class_snapshots
62
+ Array.new(@class_snapshots)
63
+ end
64
+
65
+ end
66
+ end
67
+
@@ -0,0 +1,58 @@
1
+ Maglev.persistent do
2
+ class ::Class
3
+ def exist!
4
+ @exists = true
5
+ end
6
+
7
+ def start_existence_test!
8
+ @exists = false
9
+ end
10
+
11
+ def exists?
12
+ return true if @exists
13
+ false
14
+ end
15
+ end
16
+ end
17
+
18
+ module MaglevRecord
19
+ module Snapshotable
20
+ def self.snapshotable_classes
21
+ classes = []
22
+ Object.constants.each { |constant|
23
+ begin
24
+ cls = Object.const_get constant
25
+ rescue Exception
26
+ else
27
+ classes << cls if cls.is_a? Class and cls.ancestors.include? self
28
+ end
29
+ }
30
+ classes
31
+ end
32
+
33
+ module ClassMethods
34
+
35
+ def self.extended(base)
36
+ base.exist! if base.respond_to? :exist!
37
+ end
38
+
39
+ def file_paths
40
+ (self.instance_methods(false).map { |m|
41
+ self.instance_method(m).source_location.first
42
+ } + self.methods(false).map { |m|
43
+ self.method(m).source_location.first
44
+ }).uniq
45
+ end
46
+
47
+ def has_definitions?
48
+ # TODO: maybe in a nested transaction?
49
+ start_existence_test!
50
+ file_paths.each{ |file_path|
51
+ Kernel.load file_path if File.file? file_path
52
+ return true if exists?
53
+ }
54
+ exists?
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,5 @@
1
+ require "maglev_record/snapshot/snapshotable"
2
+ require "maglev_record/snapshot/change"
3
+ require "maglev_record/snapshot/snapshot"
4
+
5
+
@@ -0,0 +1,189 @@
1
+
2
+
3
+ class Object
4
+ #
5
+ # breadth first search for references from the given object to self
6
+ #
7
+ def reference_path_to(to_object, length, trace = false)
8
+ paths = [[to_object]]
9
+ traversed = IdentitySet.new
10
+ traversed.add(to_object)
11
+ start_size = 1 if trace
12
+ while not paths.empty? and paths.first.size <= length
13
+ references = paths[0][0].find_references_in_memory
14
+ # if we print here a SecurityError mey occur
15
+ references.each{ |reference|
16
+ return [reference] + paths[0] if reference.equal?(self)
17
+ unless traversed.include?(reference) or paths.any?{ |path| reference.equal?(path)}
18
+ paths.push([reference] + paths[0])
19
+ traversed.add(reference)
20
+ end
21
+ }
22
+ if trace and start_size != paths[0].size
23
+ puts "reference_path_length: #{paths[0].size}"
24
+ start_size = paths[0].size
25
+ end
26
+ paths.delete_at(0)
27
+ end
28
+ return nil
29
+ end
30
+
31
+ def __hash_key_value
32
+ begin
33
+ assoc_value = instance_variable_defined?(:@_st_value)
34
+ assoc_key = instance_variable_defined?(:@_st_key)
35
+ rescue NameError
36
+ return nil
37
+ end
38
+ return nil unless assoc_key and assoc_value
39
+ return [assoc_key, assoc_value]
40
+ end
41
+
42
+ def __hash_key_value_equal_to(anObject)
43
+ value = __hash_key_value
44
+ return nil if value.nil?
45
+ assoc_key, assoc_value = value
46
+ return nil unless assoc_key.equal?(anObject) or assoc_value.equal?(anObject)
47
+ return [assoc_key, assoc_value]
48
+ end
49
+
50
+ def __instance_variable_equal_to(anObject)
51
+ return nil unless self.respond_to?(:instance_variables) and self.respond_to?(:instance_variable_get)
52
+ self.instance_variables.each{ |v|
53
+ return v if self.instance_variable_get(v).equal?(anObject)
54
+ }
55
+ return nil
56
+ end
57
+
58
+ def __eigenclass_equal_to(anObject)
59
+ # breaks maglev if this is used by
60
+ # maglev-ruby -e "require 'object_reference'; o = Object.new; start = Time.now; f = o.string_reference_path_to(true, 20); p start - Time.now; puts f"
61
+ return false if self.class.equal?(Array)
62
+ eigenclass = class << self
63
+ self
64
+ end
65
+ eigenclass.equal? anObject
66
+ end
67
+
68
+ def __incuded_module_equal_to(anObject)
69
+ included_modules.any?{ |m| m.equal?(anObject)} if respond_to? :included_modules
70
+ end
71
+
72
+ # format the reference path
73
+ # returns a human readable string
74
+ #
75
+ # length
76
+ # the maximum length of the path
77
+ #
78
+ # width_of_line
79
+ # the maximum size of a line
80
+ #
81
+ # trace
82
+ # true if reference_path_length shall be printed to stdout to trace the progress
83
+ # false otherwise
84
+ #
85
+ # pretty
86
+ # true if module includes shall be detected
87
+ # false if maglev internals shall be revealed
88
+ #
89
+ def string_reference_path_to(to_object, length = 10, width_of_line = 80, trace = true, pretty = true)
90
+ reference_path = reference_path_to(to_object, length, trace)
91
+ return "" if reference_path.nil?
92
+ lines = []
93
+ left_column_size = 0
94
+ referenced_index = 0
95
+ while referenced_index < reference_path.size - 1
96
+ # prepare loop
97
+ object = reference_path[referenced_index]
98
+ referenced = reference_path[referenced_index + 1]
99
+ referenced_index += 1
100
+ name_of_referenced = '?? of'
101
+ inspect_string = nil
102
+ # switch case on displaying references
103
+ begin
104
+ # puts "#obj: #{object.inspect} #{referenced.inspect} at: #{referenced_index}\n\n"
105
+ # object --> class
106
+ if object.class.equal?(referenced)
107
+ name_of_referenced = 'class of'
108
+ # class --> superclass
109
+ elsif object.respond_to? :superclass and object.superclass.equal?(referenced)
110
+ name_of_referenced = 'superclass of'
111
+ # included
112
+ elsif pretty and object.__incuded_module_equal_to(reference_path[referenced_index + 2])
113
+ name_of_referenced = 'included by'
114
+ referenced = reference_path[referenced_index + 2]
115
+ referenced_index += 2
116
+ # OrderPreservingHashAssociation --> ...
117
+ elsif not object.__hash_key_value_equal_to(referenced).nil?
118
+ assoc_key, assoc_value = object.__hash_key_value_equal_to(referenced)
119
+ if assoc_value.equal?(referenced)
120
+ name_of_referenced = 'value of'
121
+ elsif assoc_key.equal?(referenced)
122
+ name_of_referenced = 'key of'
123
+ end
124
+ # ... --> OrderPreservingHashAssociation
125
+ elsif not referenced.__hash_key_value.nil?
126
+ assoc_key, assoc_value = referenced.__hash_key_value
127
+ inspect_string = "#{assoc_key.inspect} => #{assoc_value.inspect}"
128
+ name_of_referenced = 'association in'
129
+ # ... --> attribute
130
+ elsif not (variable = object.__instance_variable_equal_to(referenced)).nil?
131
+ name_of_referenced = variable.to_s + ' in'
132
+ # [...] -> object at index
133
+ elsif object.respond_to?(:find_index) and (index = object.find_index{ |element| element.equal?(referenced)})
134
+ name_of_referenced = "at #{index.inspect} of"
135
+ # eigenclass
136
+ elsif object.__eigenclass_equal_to(referenced)
137
+ name_of_referenced = "eigenclass of"
138
+ elsif referenced.__eigenclass_equal_to(object)
139
+ name_of_referenced = "eigenbase of"
140
+ end
141
+ rescue Exception => e
142
+ name_of_referenced = 'error'
143
+ referenced = e
144
+ end
145
+ begin
146
+ inspect_string = referenced.inspect if inspect_string.nil?
147
+ rescue
148
+ inspect_string = 'can not inspect this object'
149
+ end
150
+ lines << [name_of_referenced, inspect_string]
151
+ left_column_size = name_of_referenced.size if name_of_referenced.size > left_column_size
152
+ end
153
+ width_of_line -= 8 # subtract additional characters like ' is ' ' of '
154
+ right_column_size = width_of_line - left_column_size
155
+ right_column_size = 10 if right_column_size < 0
156
+ s = ""
157
+ lines.reverse.each{ |line|
158
+ s += "#{line[1][0..right_column_size]} is \n#{line[0].rjust(left_column_size)} "
159
+ }
160
+ return s + "#{reference_path[0].inspect}"
161
+ end
162
+ end
163
+
164
+ # TestCases
165
+
166
+ ## Hash
167
+ # maglev-ruby -e "require 'object_reference'; d = {a:'2', b: 34}; f = d.string_reference_path_to(d[:a], 3); puts f"
168
+
169
+ ## superclass
170
+ # maglev-ruby -e "require 'object_reference'; class AA;end; class BB < AA;end; class CC < BB; end; class DD < CC; end; class EE < DD; end; puts EE.string_reference_path_to(AA, 5)"
171
+
172
+ ## instance var
173
+ # maglev-ruby -e "require 'object_reference'; class AA; attr_accessor :x end; o = Object.new; aa = AA.new; aa.x = o; puts aa.string_reference_path_to(o, 3)"
174
+
175
+ ## class and instvar
176
+ # maglev-ruby -e "require 'object_reference'; class AA; attr_accessor :x end; class OO; end;o = OO.new; aa = AA.new; aa.x = o; bb = AA.new; bb.x = aa; cc = AA.new; cc.x = bb; puts cc.string_reference_path_to(OO, 5)"
177
+
178
+ ## Object.new references true
179
+ # maglev-ruby -e "require 'object_reference'; o = Object.new; start = Time.now; f = o.string_reference_path_to(true, 20); p start - Time.now; puts f"
180
+
181
+ ## Array
182
+ # maglev-ruby -e "require 'object_reference'; a = b = []; 20.times{a = [a]}; start = Time.now; f = a.string_reference_path_to(b, 20); p start - Time.now; puts f"
183
+
184
+ ## Eigenclass (x is eigenclass of y)
185
+ # maglev-ruby -e "require 'object_reference'; class X;end; x = class <<X;self;end; puts X.string_reference_path_to(x, 5)"
186
+
187
+ ## Eigenbase ( reverse of eigenclass)
188
+ # maglev-ruby -e "require 'object_reference'; class X;end; x = class <<X;self;end; puts x.string_reference_path_to(X, 5)"
189
+
@@ -0,0 +1,42 @@
1
+ class MaglevSupport::SubmoduleFinder
2
+ def submodules_for(*constants)
3
+ whole_set = Set.new
4
+ constants.each do |constant|
5
+ @referenced_modules = Set.new
6
+ reference(constant)
7
+ whole_set = whole_set.union(@referenced_modules.select do |mod|
8
+ mod.name.to_s.include?(constant.to_s)
9
+ end)
10
+ end
11
+ constants + whole_set.to_a.sort_by do |mod| mod.name end
12
+ end
13
+
14
+ def reference(constant)
15
+ return if @referenced_modules.include?(constant)
16
+ @referenced_modules.add(constant)
17
+
18
+ submodules = constant.constants.map do |const|
19
+ begin
20
+ constant.const_get(const)
21
+ rescue Exception => e; end
22
+ end.select do |mod|
23
+ # We only want constants which are classes or modules, e.g. no Fixnums, Strings, ...
24
+ [Module, Class].include?(mod.class)
25
+ end
26
+
27
+ submodules.each do |mod|
28
+ reference(mod)
29
+ end
30
+ end
31
+ private :reference
32
+ end
33
+
34
+ if __FILE__ == $0
35
+ # EXAMPLE USAGE
36
+ require "rubygems"
37
+ require "rake"
38
+ puts "Finding all submodules of Rake."
39
+ ref_finder = SubmoduleFinder.new
40
+ referenced_modules = ref_finder.submodules_for(Rake)
41
+ puts referenced_modules.to_a.map { |mod| mod.name }.sort.inspect
42
+ end
@@ -0,0 +1,2 @@
1
+ require "maglev_record/tools/object_reference"
2
+ require "maglev_record/tools/submodule_finder"
data/lib/maglev_record.rb CHANGED
@@ -1,4 +1,60 @@
1
- require "rubygems"
2
- require "maglev_record/model_not_saved_or_reset"
3
- require "maglev_record/base"
4
- require "maglev_record/persistence"
1
+ require "active_model"
2
+ require "active_support"
3
+ require "active_support/core_ext/class/attribute"
4
+ require "maglev_record/maglev_support/maglev_support"
5
+ require "maglev_record/tools"
6
+ require "bundler/setup"
7
+ require "maglev_record/maglev_support/concern"
8
+ require "set"
9
+ require "logger"
10
+
11
+ if defined? MaglevRecord::VERSION
12
+ if defined? RootedBook
13
+ RootedBook.redo_include_and_extend
14
+ end
15
+ if defined? UnrootedBook
16
+ UnrootedBook.redo_include_and_extend
17
+ end
18
+ MaglevRecord::Migration.redo_include_and_extend
19
+ else
20
+ puts "IT IS NOT DEFINED"
21
+ # require "maglev_record/tools"
22
+ require "maglev_record/maglev_record"
23
+
24
+ require "maglev_record/snapshot"
25
+ require "maglev_record/maglev_support/secure_password"
26
+ require "maglev_record/sensible"
27
+ require "maglev_record/rooted_enumerable"
28
+ require "maglev_record/enumerable"
29
+ require "maglev_record/errors"
30
+ require "maglev_record/integration"
31
+ require "maglev_record/persistence"
32
+ require "maglev_record/read_write"
33
+ require "maglev_record/rooted_persistence"
34
+ require "maglev_record/migration"
35
+ require "maglev_record/base"
36
+ require "maglev_record/rooted_base"
37
+
38
+ module MaglevRecord
39
+ ref_finder = MaglevSupport::SubmoduleFinder.new
40
+ referenced_modules = ref_finder.submodules_for(MaglevRecord, MaglevSupport, Set)
41
+ MAGLEV_RECORD_PROC = Proc.new do |superklass_module|
42
+ referenced_modules.include?(superklass_module)
43
+ end
44
+
45
+ Maglev.persistent do
46
+ class ::Module
47
+ def maglev_record_persistable
48
+ self.maglev_persistable(true, &MAGLEV_RECORD_PROC)
49
+ end
50
+ end
51
+ end
52
+
53
+ referenced_modules.each do |mod|
54
+ mod.maglev_record_persistable
55
+ end
56
+ end
57
+ end
58
+
59
+ ActiveModel::Errors.maglev_nil_references
60
+ Maglev.commit_transaction
@@ -0,0 +1,38 @@
1
+ require "maglev_record/migration"
2
+ require "time"
3
+ require "logger"
4
+ require "fileutils"
5
+
6
+ MIGRATION_FOLDER = "migrations"
7
+
8
+ desc "transform the maglev database"
9
+ namespace :migrate do
10
+
11
+ desc "set up the project for migrations"
12
+ task :setup do
13
+ # puts "PID: #{Process.pid} stone: #{Maglev::System.stone_name}"
14
+ FileUtils.mkpath(MIGRATION_FOLDER) unless File.directory?(MIGRATION_FOLDER)
15
+ end
16
+
17
+ desc "migrate all the migrations in the migration folder"
18
+ task :up => :setup do
19
+ loader = MaglevRecord::MigrationLoader.new
20
+ loader.load_directory(MIGRATION_FOLDER)
21
+ migrator = MaglevRecord::Migrator.new(loader.migration_list)
22
+ logger = Logger.new(STDOUT)
23
+ migrator.up(logger)
24
+ end
25
+
26
+ desc "create a new migration in the migration folder"
27
+ task :new => :setup do
28
+ now = Time.now
29
+ filename = now.strftime("migration_%Y-%m-%b-%d_%H.%M.%S.rb")
30
+ content = MaglevRecord::Migration.file_content(now, 'fill in description here')
31
+ filepath = File.join(MIGRATION_FOLDER, filename)
32
+ File.open(filepath, 'w') { |file|
33
+ file.write(content)
34
+ }
35
+ puts "created migration #{filepath}"
36
+ end
37
+ end
38
+
@@ -0,0 +1,17 @@
1
+ require File.expand_path "lib/maglev_record/maglev_record"
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'maglevrecord'
5
+ s.version = MaglevRecord::VERSION
6
+ s.date = '2013-05-06'
7
+ s.summary = "MagLev persistence with an ActiveRecord-like interface!"
8
+ s.description = "Library for using to MagLev to persist your data in a Rails app."
9
+ s.authors = ["Dimitri Korsch", "Kirstin Heidler", "Nicco Kunzmann", "Matthias Springer", "Stefan Bunk"]
10
+ s.files = `git ls-files`.split("\n")
11
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
12
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ s.email = "bp2012h1@hpi.uni-potsdam.de"
14
+ s.homepage = 'https://github.com/knub/maglevrecord'
15
+ s.require_path = 'lib'
16
+
17
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ Kernel.load File.join(File.dirname(__FILE__), '..', 'init.rb')
@@ -0,0 +1,70 @@
1
+ require "maglev_record"
2
+
3
+ # use
4
+ # bundle exec rake test TESTOPTS="-v" TEST=test/_test_object_reference.rb
5
+
6
+
7
+ module Mod
8
+
9
+ end
10
+
11
+ class AA
12
+ include Mod
13
+ attr_accessor :x
14
+ end
15
+ class BB < AA
16
+ end
17
+ class CC < BB
18
+ end
19
+ class DD < CC
20
+ end
21
+ class EE < DD
22
+ end
23
+ class OO
24
+ end
25
+ class X
26
+ end
27
+
28
+ o = OO.new
29
+ d = {a:'2', b: 34}
30
+ aa = AA.new
31
+ aa.x = o;
32
+ bb = AA.new
33
+ bb.x = aa
34
+ cc = AA.new
35
+ cc.x = bb
36
+ a = b = []
37
+ 20.times{ a = [a] }
38
+ x = class << X
39
+ self
40
+ end
41
+
42
+ def self.assert_equal(v1, v2)
43
+ raise "expected \n#{v1.inspect}\n == \n#{v2.inspect}" unless v1 == v2
44
+ end
45
+
46
+ puts 'test_hash'
47
+ assert_equal d.string_reference_path_to(d[:a], 3), "\"2\" is \n value of :a => \"2\" is \nassociation in {:a=>\"2\", :b=>34}"
48
+
49
+ puts 'test_superclass'
50
+ assert_equal EE.string_reference_path_to(AA, 5), "AA is \nsuperclass of BB is \nsuperclass of CC is \nsuperclass of DD is \nsuperclass of EE"
51
+
52
+ puts 'test_instance_variable'
53
+ assert_equal aa.string_reference_path_to(o, 3), "#{o.inspect} is \n@x in #{aa.inspect}"
54
+
55
+ puts 'test_class_to_inst_var'
56
+ assert_equal cc.string_reference_path_to(OO, 5), "OO is \nclass of #{o.inspect} is \n @x in #{aa.inspect} is \n @x in #{bb.inspect} is \n @x in #{cc.inspect}"
57
+
58
+ puts 'test_array'
59
+ assert_equal a.string_reference_path_to(b, 20), "[] is \nat 0 of [[]] is \nat 0 of [[[]]] is \nat 0 of [[[[]]]] is \nat 0 of [[[[[]]]]] is \nat 0 of [[[[[[]]]]]] is \nat 0 of [[[[[[[]]]]]]] is \nat 0 of [[[[[[[[]]]]]]]] is \nat 0 of [[[[[[[[[]]]]]]]]] is \nat 0 of [[[[[[[[[[]]]]]]]]]] is \nat 0 of [[[[[[[[[[[]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[]]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[[]]]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[[[]]]]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]] is \nat 0 of [[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]"
60
+
61
+ puts 'test_eigenclass'
62
+ assert_equal X.string_reference_path_to(x, 5), "#{x.inspect} is \neigenclass of X"
63
+
64
+ puts 'test_eigenclass_base'
65
+ assert_equal x.string_reference_path_to(X, 5), "X is \neigenbase of #{x.inspect}"
66
+
67
+ puts 'test_include'
68
+ assert_equal AA.string_reference_path_to(Mod, 5), "Mod is \nincluded by AA"
69
+
70
+ puts 'done!'
@@ -1,19 +1,32 @@
1
- require "maglev_record"
2
-
3
1
  class Book
4
- include MaglevRecord::Base
5
-
2
+ include MaglevRecord::ReadWrite
6
3
  attr_accessor :author, :title, :comments
7
-
8
- validates :author, :presence => true
9
- validates :title, :presence => true,
10
- :length => { :minimum => 5 }
11
-
12
- def to_s
13
- title
4
+ def self.example_params
5
+ { :author => "Author", :title => "Title" }
6
+ end
7
+ def self.example
8
+ self.new(example_params)
14
9
  end
10
+ end
15
11
 
16
- def self.dummy
17
- Book.new(:title => "Harry Potter and the Chamber of Secrets", :author => "Joanne K. Rowling")
12
+ class RootedBook < Book
13
+ include MaglevRecord::RootedBase
14
+ def book
15
+ puts "I am a RootedBook"
18
16
  end
19
17
  end
18
+
19
+ class UnrootedBook < Book
20
+ include MaglevRecord::Base
21
+ end
22
+
23
+ Book.maglev_record_persistable
24
+ RootedBook.maglev_record_persistable
25
+ UnrootedBook.maglev_record_persistable
26
+ Maglev.commit_transaction
27
+
28
+ class RootedBook
29
+ include ActiveModel::Validations
30
+ validates :author, :presence => true,
31
+ :length => { :minimum => 4 }
32
+ end
@@ -0,0 +1,8 @@
1
+ Migration.new(Time.utc(2013, 2, 1, 10, 0, 0, 0), "Creating a global variable $DUMMY") do
2
+ def up
3
+ $DUMMY = 1
4
+ end
5
+ def down
6
+ $DUMMY = nil
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ Migration.new(Time.utc(2014, 2, 1, 10, 0, 0, 0), "Multiplying $DUMMY by 2") do
2
+ def up
3
+ $DUMMY *= 2
4
+ end
5
+ def down
6
+ $DUMMY /= 2
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ Migration.new(Time.utc(2015, 2, 1, 10, 0, 0, 0), "Adding 1 to $DUMMY") do
2
+ def up
3
+ $DUMMY += 1
4
+ end
5
+ def down
6
+ $DUMMY -= 1
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ Migration.new(Time.utc(2013, 2, 1, 10, 0, 0, 0), "Change book title") do
2
+ def up
3
+ RootedBook.each do |book|
4
+ book.title = "A new book title"
5
+ end
6
+ end
7
+ def down
8
+ RootedBook.each do |book|
9
+ book.title = "Back to old title"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ Migration.new(Time.utc(2014, 2, 1, 10, 0, 0, 0), "Change book title again") do
2
+ def up
3
+ RootedBook.each do |book|
4
+ book.title = "A even newer book title"
5
+ end
6
+ end
7
+ def down
8
+ RootedBook.each do |book|
9
+ book.title = "A new book title"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ Migration.new(Time.utc(2015, 2, 1, 10, 0, 0, 0), "Change book title to most recent one") do
2
+ def up
3
+ RootedBook.each do |book|
4
+ book.title = "The most recent book title"
5
+ end
6
+ end
7
+ def down
8
+ RootedBook.each do |book|
9
+ book.title = "A even newer book title"
10
+ end
11
+ end
12
+ end