maglevrecord 0.0.3 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +35 -0
- data/.travis.yml +19 -0
- data/Gemfile +13 -0
- data/README.md +89 -0
- data/Rakefile +22 -0
- data/install.sh +238 -0
- data/lib/maglev_record/base.rb +10 -62
- data/lib/maglev_record/enumerable.rb +13 -24
- data/lib/maglev_record/errors.rb +10 -0
- data/lib/maglev_record/integration.rb +7 -0
- data/lib/maglev_record/maglev_record.rb +13 -0
- data/lib/maglev_record/maglev_support/active_support_patch.rb +31 -0
- data/lib/maglev_record/maglev_support/concern.rb +19 -0
- data/lib/maglev_record/maglev_support/maglev_support.rb +15 -0
- data/lib/maglev_record/maglev_support/secure_password.rb +39 -0
- data/lib/maglev_record/migration/loader.rb +38 -0
- data/lib/maglev_record/migration/migration.rb +142 -0
- data/lib/maglev_record/migration/migrator.rb +40 -0
- data/lib/maglev_record/migration/operations.rb +92 -0
- data/lib/maglev_record/migration.rb +5 -0
- data/lib/maglev_record/persistence.rb +23 -48
- data/lib/maglev_record/raketasks.rb +9 -0
- data/lib/maglev_record/read_write.rb +20 -10
- data/lib/maglev_record/rooted_base.rb +8 -0
- data/lib/maglev_record/rooted_enumerable.rb +25 -0
- data/lib/maglev_record/rooted_persistence.rb +36 -0
- data/lib/maglev_record/sensible.rb +28 -0
- data/lib/maglev_record/snapshot/change.rb +53 -0
- data/lib/maglev_record/snapshot/snapshot.rb +67 -0
- data/lib/maglev_record/snapshot/snapshotable.rb +58 -0
- data/lib/maglev_record/snapshot.rb +5 -0
- data/lib/maglev_record/tools/object_reference.rb +189 -0
- data/lib/maglev_record/tools/submodule_finder.rb +42 -0
- data/lib/maglev_record/tools.rb +2 -0
- data/lib/maglev_record.rb +60 -4
- data/lib/tasks/database.rake +38 -0
- data/maglevrecord.gemspec +17 -0
- data/rails/init.rb +1 -0
- data/test/_test_object_reference.rb +70 -0
- data/test/example_model.rb +26 -13
- data/test/migration/dummy_migrations/migration_1.rb +8 -0
- data/test/migration/dummy_migrations/migration_2.rb +8 -0
- data/test/migration/dummy_migrations/migration_3.rb +8 -0
- data/test/migration/migrations/migration_1.rb +12 -0
- data/test/migration/migrations/migration_2.rb +12 -0
- data/test/migration/migrations/migration_3.rb +12 -0
- data/test/migration/operation_setup.rb +91 -0
- data/test/migration/projects/project1/.gitignore +15 -0
- data/test/migration/projects/project1/Gemfile +43 -0
- data/test/migration/projects/project1/Gemfile.lock +114 -0
- data/test/migration/projects/project1/README.rdoc +261 -0
- data/test/migration/projects/project1/Rakefile +17 -0
- data/test/migration/projects/project1/app/assets/images/rails.png +0 -0
- data/test/migration/projects/project1/app/assets/javascripts/application.js +15 -0
- data/test/migration/projects/project1/app/assets/stylesheets/application.css +13 -0
- data/test/migration/projects/project1/app/controllers/application_controller.rb +3 -0
- data/test/migration/projects/project1/app/helpers/application_helper.rb +2 -0
- data/test/migration/projects/project1/app/mailers/.gitkeep +0 -0
- data/test/migration/projects/project1/app/models/.gitkeep +0 -0
- data/test/migration/projects/project1/app/views/layouts/application.html.erb +14 -0
- data/test/migration/projects/project1/config/application.rb +62 -0
- data/test/migration/projects/project1/config/boot.rb +6 -0
- data/test/migration/projects/project1/config/database.yml +25 -0
- data/test/migration/projects/project1/config/environment.rb +5 -0
- data/test/migration/projects/project1/config/environments/development.rb +37 -0
- data/test/migration/projects/project1/config/environments/production.rb +67 -0
- data/test/migration/projects/project1/config/initializers/backtrace_silencers.rb +7 -0
- data/test/migration/projects/project1/config/initializers/inflections.rb +15 -0
- data/test/migration/projects/project1/config/initializers/mime_types.rb +5 -0
- data/test/migration/projects/project1/config/initializers/secret_token.rb +7 -0
- data/test/migration/projects/project1/config/initializers/session_store.rb +8 -0
- data/test/migration/projects/project1/config/initializers/wrap_parameters.rb +14 -0
- data/test/migration/projects/project1/config/locales/en.yml +5 -0
- data/test/migration/projects/project1/config/routes.rb +58 -0
- data/test/migration/projects/project1/config.ru +4 -0
- data/test/migration/projects/project1/db/seeds.rb +7 -0
- data/test/migration/projects/project1/lib/assets/.gitkeep +0 -0
- data/test/migration/projects/project1/lib/tasks/.gitkeep +0 -0
- data/test/migration/projects/project1/log/.gitkeep +0 -0
- data/test/migration/projects/project1/public/404.html +26 -0
- data/test/migration/projects/project1/public/422.html +26 -0
- data/test/migration/projects/project1/public/500.html +25 -0
- data/test/migration/projects/project1/public/favicon.ico +0 -0
- data/test/migration/projects/project1/public/index.html +241 -0
- data/test/migration/projects/project1/public/robots.txt +5 -0
- data/test/migration/projects/project1/script/rails +6 -0
- data/test/migration/projects/project2/.gitignore +15 -0
- data/test/migration/projects/project2/Gemfile +44 -0
- data/test/migration/projects/project2/Gemfile.lock +115 -0
- data/test/migration/projects/project2/README.rdoc +261 -0
- data/test/migration/projects/project2/Rakefile +17 -0
- data/test/migration/projects/project2/app/assets/images/rails.png +0 -0
- data/test/migration/projects/project2/app/assets/javascripts/application.js +15 -0
- data/test/migration/projects/project2/app/assets/stylesheets/application.css +13 -0
- data/test/migration/projects/project2/app/controllers/application_controller.rb +3 -0
- data/test/migration/projects/project2/app/helpers/application_helper.rb +2 -0
- data/test/migration/projects/project2/app/mailers/.gitkeep +0 -0
- data/test/migration/projects/project2/app/models/.gitkeep +0 -0
- data/test/migration/projects/project2/app/models/project_model.rb +8 -0
- data/test/migration/projects/project2/app/views/layouts/application.html.erb +14 -0
- data/test/migration/projects/project2/config/application.rb +62 -0
- data/test/migration/projects/project2/config/boot.rb +6 -0
- data/test/migration/projects/project2/config/database.yml +25 -0
- data/test/migration/projects/project2/config/environment.rb +5 -0
- data/test/migration/projects/project2/config/environments/development.rb +37 -0
- data/test/migration/projects/project2/config/environments/production.rb +67 -0
- data/test/migration/projects/project2/config/initializers/backtrace_silencers.rb +7 -0
- data/test/migration/projects/project2/config/initializers/inflections.rb +15 -0
- data/test/migration/projects/project2/config/initializers/mime_types.rb +5 -0
- data/test/migration/projects/project2/config/initializers/secret_token.rb +7 -0
- data/test/migration/projects/project2/config/initializers/session_store.rb +8 -0
- data/test/migration/projects/project2/config/initializers/wrap_parameters.rb +14 -0
- data/test/migration/projects/project2/config/locales/en.yml +5 -0
- data/test/migration/projects/project2/config/routes.rb +58 -0
- data/test/migration/projects/project2/config.ru +4 -0
- data/test/migration/projects/project2/db/seeds.rb +7 -0
- data/test/migration/projects/project2/lib/assets/.gitkeep +0 -0
- data/test/migration/projects/project2/lib/tasks/.gitkeep +0 -0
- data/test/migration/projects/project2/log/.gitkeep +0 -0
- data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.31.38.rb +16 -0
- data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.31.52.rb +16 -0
- data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.32.07.rb +16 -0
- data/test/migration/projects/project2/public/404.html +26 -0
- data/test/migration/projects/project2/public/422.html +26 -0
- data/test/migration/projects/project2/public/500.html +25 -0
- data/test/migration/projects/project2/public/favicon.ico +0 -0
- data/test/migration/projects/project2/public/index.html +241 -0
- data/test/migration/projects/project2/public/robots.txt +5 -0
- data/test/migration/projects/project2/script/rails +6 -0
- data/test/migration/test_loader.rb +78 -0
- data/test/migration/test_migration.rb +127 -0
- data/test/migration/test_nonexistent_classes.rb +120 -0
- data/test/migration/test_operations_fit_together.rb +68 -0
- data/test/migration/test_project.rb +105 -0
- data/test/migration/test_project1.slow.rb +58 -0
- data/test/migration/test_project2.slow.rb +34 -0
- data/test/migration/test_remove.rb +219 -0
- data/test/migration/test_rename.rb +238 -0
- data/test/migration/test_scenario.rb +37 -0
- data/test/migration/todo.txt +17 -0
- data/test/more_asserts.rb +63 -0
- data/test/snapshot/test_snapshot.rb +99 -0
- data/test/snapshot/test_snapshot_attributes.slow.rb +57 -0
- data/test/snapshot/test_snapshot_classes.slow.rb +32 -0
- data/test/snapshot/test_snapshotable.rb +53 -0
- data/test/test_accessors.rb +46 -0
- data/test/test_active_model_like_interface.rb +1 -1
- data/test/test_model_timestamps.rb +22 -0
- data/test/test_more_asserts.rb +68 -0
- data/test/test_naming.rb +22 -0
- data/test/test_persistence.rb +127 -0
- data/test/test_query_interface.rb +20 -25
- data/test/test_sensibles.rb +38 -0
- data/test/test_validation.rb +20 -57
- data/todo.txt +1 -0
- data/update.sh +180 -0
- metadata +156 -12
- data/lib/maglev_record/model_not_saved_or_reset.rb +0 -15
- data/test/test_dirty_object.rb +0 -50
- data/test/test_maglev_record_base.rb +0 -22
- 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,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
|
data/lib/maglev_record.rb
CHANGED
@@ -1,4 +1,60 @@
|
|
1
|
-
require "
|
2
|
-
require "
|
3
|
-
require "
|
4
|
-
require "maglev_record/
|
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!'
|
data/test/example_model.rb
CHANGED
@@ -1,19 +1,32 @@
|
|
1
|
-
require "maglev_record"
|
2
|
-
|
3
1
|
class Book
|
4
|
-
include MaglevRecord::
|
5
|
-
|
2
|
+
include MaglevRecord::ReadWrite
|
6
3
|
attr_accessor :author, :title, :comments
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
17
|
-
|
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,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
|