maglevrecord 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +7 -0
- data/.travis.yml +0 -1
- data/README.md +22 -7
- data/Rakefile +2 -2
- data/install.sh +0 -1
- data/lib/maglev_record/base.rb +10 -1
- data/lib/maglev_record/enumerable.rb +6 -1
- data/lib/maglev_record/errors.rb +3 -0
- data/lib/maglev_record/maglev_record.rb +1 -1
- data/lib/maglev_record/maglev_support/concern.rb +2 -3
- data/lib/maglev_record/maglev_support/secure_password.rb +2 -3
- data/lib/maglev_record/migration/loader.rb +1 -1
- data/lib/maglev_record/migration/migration.rb +14 -0
- data/lib/maglev_record/migration/migrator.rb +22 -4
- data/lib/maglev_record/migration/operations.rb +58 -0
- data/lib/maglev_record/persistence.rb +12 -5
- data/lib/maglev_record/read_write.rb +38 -7
- data/lib/maglev_record/rooted_enumerable.rb +6 -1
- data/lib/maglev_record/rooted_persistence.rb +4 -0
- data/lib/maglev_record/sensible.rb +2 -2
- data/lib/maglev_record/snapshot/change.rb +54 -15
- data/lib/maglev_record/snapshot/class_change.rb +66 -0
- data/lib/maglev_record/snapshot/class_snapshot.rb +63 -0
- data/lib/maglev_record/snapshot/snapshot.rb +44 -38
- data/lib/maglev_record/snapshot/snapshotable.rb +81 -26
- data/lib/maglev_record/snapshot/superclass_mismatch_change.rb +143 -0
- data/lib/maglev_record/snapshot.rb +3 -2
- data/lib/maglev_record/validations.rb +49 -0
- data/lib/maglev_record.rb +3 -2
- data/lib/tasks/database.rake +61 -17
- data/test/automigration/rake_task_base.rb +57 -0
- data/test/automigration/test_auto.slow.rb +38 -0
- data/test/automigration/test_migration_string.rb +173 -0
- data/test/automigration/test_rake_task_preconditions.slow.rb +41 -0
- data/test/automigration/test_show.slow.rb +21 -0
- data/test/automigration/test_superclass_mismatch.rb +96 -0
- data/test/example_model.rb +7 -5
- data/test/migration/base_lectures.rb +30 -0
- data/test/migration/operation_setup.rb +66 -56
- data/test/migration/projects/automigration/.gitignore +15 -0
- data/test/migration/projects/automigration/Gemfile +44 -0
- data/test/migration/projects/automigration/Gemfile.lock +115 -0
- data/test/migration/projects/automigration/README.rdoc +261 -0
- data/test/migration/projects/automigration/Rakefile +17 -0
- data/test/migration/projects/automigration/app/assets/images/rails.png +0 -0
- data/test/migration/projects/automigration/app/assets/javascripts/application.js +15 -0
- data/test/migration/projects/automigration/app/assets/stylesheets/application.css +13 -0
- data/test/migration/projects/automigration/app/controllers/application_controller.rb +3 -0
- data/test/migration/projects/automigration/app/helpers/application_helper.rb +2 -0
- data/test/migration/projects/automigration/app/mailers/.gitkeep +0 -0
- data/test/migration/projects/automigration/app/models/.gitkeep +0 -0
- data/test/migration/projects/automigration/app/models/project_model.rb +8 -0
- data/test/migration/projects/automigration/app/views/layouts/application.html.erb +14 -0
- data/test/migration/projects/automigration/config/application.rb +62 -0
- data/test/migration/projects/automigration/config/boot.rb +6 -0
- data/test/migration/projects/automigration/config/database.yml +25 -0
- data/test/migration/projects/automigration/config/environment.rb +5 -0
- data/test/migration/projects/automigration/config/environments/development.rb +37 -0
- data/test/migration/projects/automigration/config/environments/production.rb +67 -0
- data/test/migration/projects/automigration/config/initializers/backtrace_silencers.rb +7 -0
- data/test/migration/projects/automigration/config/initializers/inflections.rb +15 -0
- data/test/migration/projects/automigration/config/initializers/mime_types.rb +5 -0
- data/test/migration/projects/automigration/config/initializers/secret_token.rb +7 -0
- data/test/migration/projects/automigration/config/initializers/session_store.rb +8 -0
- data/test/migration/projects/automigration/config/initializers/wrap_parameters.rb +14 -0
- data/test/migration/projects/automigration/config/locales/en.yml +5 -0
- data/test/migration/projects/automigration/config/routes.rb +58 -0
- data/test/migration/projects/automigration/config.ru +4 -0
- data/test/migration/projects/automigration/db/seeds.rb +7 -0
- data/test/migration/projects/automigration/lib/assets/.gitkeep +0 -0
- data/test/migration/projects/automigration/lib/tasks/.gitkeep +0 -0
- data/test/migration/projects/automigration/log/.gitkeep +0 -0
- data/test/migration/projects/automigration/public/404.html +26 -0
- data/test/migration/projects/automigration/public/422.html +26 -0
- data/test/migration/projects/automigration/public/500.html +25 -0
- data/test/migration/projects/automigration/public/favicon.ico +0 -0
- data/test/migration/projects/automigration/public/index.html +241 -0
- data/test/migration/projects/automigration/public/robots.txt +5 -0
- data/test/migration/projects/automigration/script/rails +6 -0
- data/test/migration/projects/project2/Rakefile +2 -2
- data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.31.38.rb +1 -1
- data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.31.52.rb +1 -1
- data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.32.07.rb +1 -1
- data/test/migration/test_change_superclass.rb +111 -0
- data/test/migration/test_loader.rb +6 -0
- data/test/migration/test_project.rb +1 -29
- data/test/migration/test_project1.slow.rb +1 -0
- data/test/migration/test_project2.slow.rb +7 -0
- data/test/migration/test_remove.rb +123 -2
- data/test/migration/todo.txt +1 -1
- data/test/more_asserts.rb +1 -1
- data/test/snapshot/test_attributes.rb +33 -0
- data/test/snapshot/{test_snapshot_attributes.slow.rb → test_attributes.slow.rb} +3 -5
- data/test/snapshot/test_classes.rb +32 -0
- data/test/snapshot/{test_snapshot_classes.slow.rb → test_classes.slow.rb} +1 -1
- data/test/snapshot/test_from_file_system.rb +113 -0
- data/test/snapshot/test_methods.rb +136 -0
- data/test/snapshot/test_methods.slow.rb +67 -0
- data/test/snapshot/test_reset.rb +68 -0
- data/test/snapshot/test_snapshot.rb +41 -75
- data/test/snapshot/test_snapshot.slow.rb +98 -0
- data/test/snapshot/test_snapshotable.rb +0 -1
- data/test/temp_dir_test.rb +40 -0
- data/test/test_active_model_like_interface.rb +4 -1
- data/test/test_model_timestamps.rb +13 -5
- data/test/test_query_interface.rb +10 -0
- data/test/test_sensibles.rb +18 -10
- data/test/test_validation.rb +2 -12
- metadata +64 -5
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
# MagLevRecord - a model interface for Rails
|
1
|
+
# MagLevRecord - a model interface for Rails
|
2
|
+
[](https://travis-ci.org/knub/maglevrecord)
|
3
|
+
[](https://codeclimate.com/github/knub/maglevrecord)
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
+
```ActiveRecord``` is the ORM commonly used when working with Rails and relational databases.
|
6
|
+
When using MagLev, using an ORM is no longer necessary, **you can just work with your objects as they are**.
|
7
|
+
Still, ```ActiveRecord::Base``` offers some nice features for working with your models (*e.g.* like Validations).
|
5
8
|
|
6
|
-
This
|
9
|
+
This gem offers all those features and bundles them in a comfortable way.
|
7
10
|
|
8
|
-
|
11
|
+
### Installation
|
9
12
|
|
10
|
-
You can install this gem from rubygems.org:
|
11
13
|
```gem install maglevrecord```
|
12
14
|
|
13
15
|
|
@@ -15,7 +17,15 @@ You can install this gem from rubygems.org:
|
|
15
17
|
|
16
18
|
### Creating classes
|
17
19
|
|
18
|
-
|
20
|
+
Models, which you wish to persist, have to include ```MaglevRecord::Base``` or ```MaglevRecord::RootedBase```.
|
21
|
+
You can still inherit from whatever base class you want.
|
22
|
+
|
23
|
+
The difference between ```RootedBase``` and ```Base``` is, that ```RootedBase``` automatically stores the
|
24
|
+
instances in ```Maglev::PERSISTENT_ROOT``` ([persistence by reachability](http://maglevity.wordpress.com/2010/01/17/persistence-by-reachability/)).
|
25
|
+
The instances are stored in a hash, which contains all instances of the class.
|
26
|
+
|
27
|
+
When using ```Base``` you are responsible for making the object reachable from ```PERSISTENT_ROOT```.
|
28
|
+
|
19
29
|
|
20
30
|
```ruby
|
21
31
|
require 'maglev_record'
|
@@ -83,6 +93,11 @@ Using ```book.valid?``` you can determine if a model is valid. Models are *not*
|
|
83
93
|
|
84
94
|
Use ```MaglevRecord.reset``` the reset all changed made since the last save or reset.
|
85
95
|
|
96
|
+
|
97
|
+
### Migrating objects
|
98
|
+
|
99
|
+
Have a look at the [demo application for migrations](https://github.com/niccokunzmann/maglevrecord-demo/blob/master/README.md).
|
100
|
+
|
86
101
|
## Further questions, improvements?
|
87
102
|
|
88
103
|
Feel free to fork, pull-request or ask via email at bp2012h1 [at] hpi.uni-potsdam.de.
|
data/Rakefile
CHANGED
@@ -6,14 +6,14 @@ $LOAD_PATH << './lib'
|
|
6
6
|
Rake::TestTask.new do |t|
|
7
7
|
t.libs << 'test'
|
8
8
|
t.name = 'testfast'
|
9
|
-
t.test_files = FileList['test
|
9
|
+
t.test_files = FileList['test/{,**/}test*.rb'] - FileList['test/{,**/}test*.slow.rb']
|
10
10
|
t.ruby_opts << "-W0 -rubygems --stone test"
|
11
11
|
end
|
12
12
|
|
13
13
|
Rake::TestTask.new do |t|
|
14
14
|
t.libs << 'test'
|
15
15
|
t.name = 'testslow'
|
16
|
-
t.test_files = FileList['test
|
16
|
+
t.test_files = FileList['test/{,**/}test*.rb']
|
17
17
|
t.ruby_opts << "-W0 -rubygems --stone test"
|
18
18
|
end
|
19
19
|
|
data/install.sh
CHANGED
@@ -121,7 +121,6 @@ case "$PLATFORM" in
|
|
121
121
|
shmall="`sysctl kern.sysv.shmall | cut -f2 -d' '`"
|
122
122
|
;;
|
123
123
|
SunOS-i86pc)
|
124
|
-
# TODO: figure memory needs for Solaris-x86
|
125
124
|
# Investigate project.max-shm-memory
|
126
125
|
totalMemMB="`/usr/sbin/prtconf | grep Memory | cut -f3 -d' '`"
|
127
126
|
totalMem=$(($totalMemMB * 1048576))
|
data/lib/maglev_record/base.rb
CHANGED
@@ -1,14 +1,23 @@
|
|
1
1
|
module MaglevRecord
|
2
2
|
module Base
|
3
3
|
extend MaglevSupport::Concern
|
4
|
+
include MaglevRecord::Snapshotable
|
4
5
|
include MaglevRecord::Integration
|
5
6
|
include MaglevRecord::Persistence
|
6
7
|
include MaglevRecord::ReadWrite
|
7
8
|
include MaglevRecord::MigrationOperations
|
8
9
|
redo_include ActiveModel::Conversion
|
10
|
+
redo_include MaglevRecord::Validations
|
11
|
+
#module ClassMethods
|
12
|
+
# def self.extended(base)
|
13
|
+
#base.class_methods_not_to_reset << "_validators"
|
14
|
+
#base.class_methods_not_to_reset << "_validators="
|
15
|
+
#base.class_methods_not_to_reset << "_validators?"
|
16
|
+
#base.class_methods_not_to_reset << "method_missing"
|
17
|
+
# end
|
18
|
+
#end
|
9
19
|
include MaglevRecord::Sensible
|
10
20
|
include ActiveModel::Conversion
|
11
21
|
include MaglevRecord::SecurePassword
|
12
|
-
include MaglevRecord::Snapshotable
|
13
22
|
end
|
14
23
|
end
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module MaglevRecord
|
2
2
|
module Enumerable
|
3
3
|
module ClassMethods
|
4
|
+
def first
|
5
|
+
each{ |model|
|
6
|
+
return model
|
7
|
+
}
|
8
|
+
end
|
4
9
|
def all
|
5
10
|
raise "method not available for MaglevRecord::Base"
|
6
11
|
end
|
@@ -21,4 +26,4 @@ module MaglevRecord
|
|
21
26
|
end
|
22
27
|
end
|
23
28
|
end
|
24
|
-
end
|
29
|
+
end
|
data/lib/maglev_record/errors.rb
CHANGED
@@ -4,16 +4,15 @@ module MaglevSupport
|
|
4
4
|
self.included_modules.reverse.each do |mod|
|
5
5
|
base.extend(mod::ClassMethods) if mod.constants.include? 'ClassMethods'
|
6
6
|
end
|
7
|
+
base.extend(self::ClassMethods) if self.constants.include? 'ClassMethods'
|
7
8
|
self.reinclude_store.each do |mod|
|
8
9
|
base.__save_for_reinclude(mod)
|
9
10
|
end unless self.reinclude_store.nil?
|
10
|
-
base.extend(self::ClassMethods) if self.constants.include? 'ClassMethods'
|
11
11
|
if base.is_a? Class
|
12
|
-
# base.send :redo_include, ActiveModel::Validations
|
13
12
|
base.send :redo_extend, Enumerable
|
14
13
|
base.send :redo_extend, MaglevSupport.constantize("ActiveModel::Naming")
|
15
14
|
end
|
16
|
-
Maglev.commit_transaction
|
15
|
+
#Maglev.commit_transaction
|
17
16
|
end
|
18
17
|
end
|
19
18
|
end
|
@@ -4,9 +4,8 @@ module MaglevRecord
|
|
4
4
|
def has_secure_password
|
5
5
|
attr_reader :password
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
# validates_presence_of :password_digest
|
7
|
+
validates_confirmation_of :password
|
8
|
+
validates_presence_of :password_digest
|
10
9
|
|
11
10
|
mark_sensible :password, :password_confirmation
|
12
11
|
|
@@ -19,7 +19,7 @@ module MaglevRecord
|
|
19
19
|
|
20
20
|
def load_string(source, file = __FILE__)
|
21
21
|
migration = instance_eval source, file
|
22
|
-
|
22
|
+
raise MaglevRecord::NoMigrationReadError unless migration.class == MaglevRecord::Migration
|
23
23
|
migration.source = source
|
24
24
|
@migration_list << migration
|
25
25
|
end
|
@@ -138,5 +138,19 @@ MaglevRecord::Migration.new(Time.parse('#{
|
|
138
138
|
end
|
139
139
|
eos
|
140
140
|
end
|
141
|
+
|
142
|
+
def self.write_to_file(folder, description,
|
143
|
+
upcode = nil, downcode = nil)
|
144
|
+
now = Time.now
|
145
|
+
filename = now.strftime("migration_%Y-%m-%b-%d_%H.%M.%S.rb")
|
146
|
+
# TODO the arguments point at this to need to be refactored to an own
|
147
|
+
# class
|
148
|
+
content = file_content(now, description, upcode, downcode)
|
149
|
+
filepath = File.join(folder, filename)
|
150
|
+
File.open(filepath, 'w') { |file|
|
151
|
+
file.write(content)
|
152
|
+
}
|
153
|
+
filepath
|
154
|
+
end
|
141
155
|
end
|
142
156
|
end
|
@@ -17,16 +17,28 @@ module MaglevRecord
|
|
17
17
|
##
|
18
18
|
# Returns all migrations currently in the stone in the correct order.
|
19
19
|
def migration_store
|
20
|
-
Maglev::PERSISTENT_ROOT[MIGRATION_KEY] ||=
|
20
|
+
Maglev::PERSISTENT_ROOT[MIGRATION_KEY] ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
def migrations_todo
|
24
|
+
@migration_list.reject do |mig|
|
25
|
+
migration_store.include?(mig.id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def up?(logger = @non_displaying_logger)
|
30
|
+
# todo: test
|
31
|
+
migrations_todo.sort.each do |mig|
|
32
|
+
logger.info("to do: '" + mig.name + "' from " + mig.timestamp.to_s)
|
33
|
+
end
|
34
|
+
logger.info("Already applied all migrations.") if migrations_todo.empty?
|
21
35
|
end
|
22
36
|
|
23
37
|
##
|
24
38
|
# Applies the desired state of migrations.
|
25
39
|
def up(logger = @non_displaying_logger)
|
26
40
|
Maglev.abort_transaction
|
27
|
-
to_do =
|
28
|
-
migration_store.include?(mig.id)
|
29
|
-
end
|
41
|
+
to_do = migrations_todo
|
30
42
|
logger.info("Already applied all migrations.") if to_do.empty?
|
31
43
|
to_do.sort.each do |mig|
|
32
44
|
mig.logger = logger
|
@@ -36,5 +48,11 @@ module MaglevRecord
|
|
36
48
|
end
|
37
49
|
Maglev.commit_transaction
|
38
50
|
end
|
51
|
+
|
52
|
+
def self.for_directory(directory)
|
53
|
+
loader = MigrationLoader.new
|
54
|
+
loader.load_directory(directory)
|
55
|
+
new(loader.migration_list)
|
56
|
+
end
|
39
57
|
end
|
40
58
|
end
|
@@ -12,6 +12,7 @@ module MaglevRecord
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def rename_attribute(old_name, new_name)
|
15
|
+
# TODO: test wether attribute is removed from attributes of class
|
15
16
|
attr_accessor new_name
|
16
17
|
each { |model|
|
17
18
|
value = model.attributes[old_name]
|
@@ -30,10 +31,12 @@ module MaglevRecord
|
|
30
31
|
end
|
31
32
|
|
32
33
|
def delete_attribute(name)
|
34
|
+
# TODO: test attribute names for string and for symbol
|
33
35
|
each { |model|
|
34
36
|
value = model.attributes.delete(name)
|
35
37
|
yield value if block_given?
|
36
38
|
}
|
39
|
+
attributes.delete name.to_s if respond_to? :attributes
|
37
40
|
end
|
38
41
|
|
39
42
|
def migration_rename_to(new_name)
|
@@ -70,7 +73,46 @@ module MaglevRecord
|
|
70
73
|
}
|
71
74
|
list
|
72
75
|
end
|
76
|
+
|
77
|
+
def remove_instance_method(name)
|
78
|
+
begin
|
79
|
+
remove_method name
|
80
|
+
rescue NameError
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def remove_class_method(name)
|
85
|
+
begin
|
86
|
+
singleton_class.remove_method name
|
87
|
+
rescue NameError
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def change_superclass_to(new_superclass)
|
92
|
+
# remove the superclass to enable to change the superclass
|
93
|
+
return unless new_superclass.is_able_to_become_superclass_of(self)
|
94
|
+
_name = name
|
95
|
+
Maglev.persistent do
|
96
|
+
maglev_redefine {
|
97
|
+
new_class = Object.module_eval "
|
98
|
+
class #{_name} < #{new_superclass.name}
|
99
|
+
self
|
100
|
+
end"
|
101
|
+
if respond_to? :object_pool_key
|
102
|
+
# where should I put it else?
|
103
|
+
raise "self should be object_pool_key" unless self == object_pool_key
|
104
|
+
pool_pool = Maglev::PERSISTENT_ROOT[MaglevRecord::PERSISTENT_ROOT_KEY]
|
105
|
+
unless pool_pool.nil?
|
106
|
+
#TODO: test no instances while superclass change
|
107
|
+
old_pool = pool_pool.delete(self) # TODO: test removed
|
108
|
+
pool_pool[new_class] = old_pool unless old_pool.nil?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
73
114
|
end
|
115
|
+
|
74
116
|
class NullClass
|
75
117
|
include ClassMethods
|
76
118
|
def initialize(name)
|
@@ -86,7 +128,23 @@ module MaglevRecord
|
|
86
128
|
end
|
87
129
|
def migration_delete
|
88
130
|
end
|
131
|
+
def remove_instance_method(name)
|
132
|
+
end
|
133
|
+
def remove_class_method(name)
|
134
|
+
end
|
135
|
+
def is_able_to_become_superclass_of(base_class)
|
136
|
+
false
|
137
|
+
end
|
138
|
+
def change_superclass_to(new_superclass)
|
139
|
+
end
|
89
140
|
end
|
90
141
|
end
|
91
142
|
end
|
92
143
|
|
144
|
+
Maglev.persistent do
|
145
|
+
class Class
|
146
|
+
def is_able_to_become_superclass_of(base_class)
|
147
|
+
true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -5,18 +5,25 @@ module MaglevRecord
|
|
5
5
|
def initialize(*args)
|
6
6
|
if args.size == 1
|
7
7
|
args[0].each do |k, v|
|
8
|
-
meth_name = "#{k.to_s}=".to_sym
|
8
|
+
meth_name = "#{k.to_s}=".to_sym
|
9
9
|
self.send(meth_name, v) if self.respond_to? meth_name
|
10
10
|
end
|
11
11
|
end
|
12
|
-
|
12
|
+
created
|
13
13
|
end
|
14
14
|
|
15
15
|
def created_at
|
16
16
|
@created_at_timestamp
|
17
17
|
end
|
18
|
-
def
|
19
|
-
@created_at_timestamp =
|
18
|
+
def created
|
19
|
+
@created_at_timestamp = Time.now
|
20
|
+
end
|
21
|
+
|
22
|
+
def updated_at
|
23
|
+
@updated_at_timestamp
|
24
|
+
end
|
25
|
+
def updated
|
26
|
+
@updated_at_timestamp = Time.now
|
20
27
|
end
|
21
28
|
|
22
29
|
alias :persisted? :committed?
|
@@ -38,4 +45,4 @@ module MaglevRecord
|
|
38
45
|
end
|
39
46
|
end
|
40
47
|
end
|
41
|
-
end
|
48
|
+
end
|
@@ -4,7 +4,7 @@ module MaglevRecord
|
|
4
4
|
extend MaglevSupport::Concern
|
5
5
|
|
6
6
|
def attributes
|
7
|
-
@maglev_attributes ||= Hash.new
|
7
|
+
@maglev_attributes ||= Hash.new
|
8
8
|
end
|
9
9
|
|
10
10
|
def update_attributes(attribute_hash)
|
@@ -16,9 +16,8 @@ module MaglevRecord
|
|
16
16
|
|
17
17
|
module ClassMethods
|
18
18
|
def attr_reader(*attr_names)
|
19
|
-
@attr_readers ||= []
|
20
19
|
attr_names.each do |attr_name|
|
21
|
-
|
20
|
+
attributes << attr_name.to_s
|
22
21
|
self.module_eval <<-ATTRREADER, __FILE__, __LINE__ + 1
|
23
22
|
def #{attr_name}
|
24
23
|
attributes[:#{attr_name}]
|
@@ -27,24 +26,56 @@ module MaglevRecord
|
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
|
-
def attr_readers
|
31
|
-
@attr_readers
|
32
|
-
end
|
33
|
-
|
34
29
|
def attr_writer(*attr_names)
|
35
30
|
attr_names.each do |attr_name|
|
31
|
+
attributes << attr_name.to_s
|
36
32
|
self.module_eval <<-ATTRWRITER, __FILE__, __LINE__ + 1
|
37
33
|
def #{attr_name}=(new_value)
|
34
|
+
updated
|
38
35
|
attributes[:#{attr_name}] = new_value
|
39
36
|
end
|
40
37
|
ATTRWRITER
|
41
38
|
end
|
42
39
|
end
|
43
40
|
|
41
|
+
|
44
42
|
def attr_accessor(*attr_names)
|
45
43
|
attr_reader *attr_names
|
46
44
|
attr_writer *attr_names
|
47
45
|
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# resets the class to no methods
|
49
|
+
# returns a memento proc that can be called to restore the old state
|
50
|
+
#
|
51
|
+
def attributes
|
52
|
+
@attributes ||= []
|
53
|
+
raise TypeError, "attributes contain bad elements #{@attributes}" unless @attributes.all?{ |attribute| attribute.is_a? String }
|
54
|
+
@attributes.sort!
|
55
|
+
@attributes.uniq!
|
56
|
+
@attributes
|
57
|
+
end
|
58
|
+
|
59
|
+
def reset
|
60
|
+
_attributes = attributes_to_reset.map{ |attribute|
|
61
|
+
attributes.delete attribute
|
62
|
+
}
|
63
|
+
reset_proc = super if defined?(super)
|
64
|
+
return Proc.new {
|
65
|
+
reset_proc.call unless reset_proc.nil?
|
66
|
+
_attributes.each{ |attribute| attributes << attribute}
|
67
|
+
attributes
|
68
|
+
self
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def snapshot_attributes
|
73
|
+
attributes.reject{|attribute| attribute.include? 'valid' }
|
74
|
+
end
|
75
|
+
|
76
|
+
def attributes_to_reset
|
77
|
+
snapshot_attributes
|
78
|
+
end
|
48
79
|
end
|
49
80
|
end
|
50
81
|
end
|
@@ -2,6 +2,9 @@ module MaglevRecord
|
|
2
2
|
module RootedPersistence
|
3
3
|
extend MaglevSupport::Concern
|
4
4
|
|
5
|
+
def destroy
|
6
|
+
self.class.object_pool.delete(self.id)
|
7
|
+
end
|
5
8
|
module ClassMethods
|
6
9
|
def object_pool_key
|
7
10
|
self
|
@@ -17,6 +20,7 @@ module MaglevRecord
|
|
17
20
|
end
|
18
21
|
|
19
22
|
def new(*args)
|
23
|
+
create_validations
|
20
24
|
instance = super(*args)
|
21
25
|
self.object_pool[instance.id] = instance
|
22
26
|
instance
|
@@ -5,7 +5,7 @@ module MaglevRecord
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def clear_sensibles
|
8
|
-
sensibles.each do |attribute|
|
8
|
+
sensibles.each do |attribute|
|
9
9
|
send("#{attribute}=", nil)
|
10
10
|
end
|
11
11
|
end
|
@@ -17,7 +17,7 @@ module MaglevRecord
|
|
17
17
|
|
18
18
|
def mark_sensible(*attr_names)
|
19
19
|
@maglev_sensible_attributes ||= Array.new unless attr_names.empty?
|
20
|
-
attr_names.each do |attribute|
|
20
|
+
attr_names.each do |attribute|
|
21
21
|
@maglev_sensible_attributes << attribute unless @maglev_sensible_attributes.include?(attribute)
|
22
22
|
end
|
23
23
|
end
|
@@ -1,19 +1,9 @@
|
|
1
1
|
|
2
2
|
module MaglevRecord
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
@new = new
|
8
|
-
end
|
9
|
-
def new_attr_accessors
|
10
|
-
@new.attr_readers - @old.attr_readers
|
11
|
-
end
|
12
|
-
def removed_attr_accessors
|
13
|
-
@old.attr_readers - @new.attr_readers
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
4
|
+
#
|
5
|
+
# The Change between two snapshots of the image
|
6
|
+
#
|
17
7
|
class Change
|
18
8
|
|
19
9
|
def initialize(old, new)
|
@@ -34,14 +24,22 @@ module MaglevRecord
|
|
34
24
|
changes
|
35
25
|
end
|
36
26
|
|
27
|
+
def changed_class_names
|
28
|
+
changed_classes.map(&:class_name).sort
|
29
|
+
end
|
30
|
+
|
37
31
|
def removed_classes
|
38
|
-
@
|
39
|
-
|
32
|
+
@old.class_snapshots.select{ |old|
|
33
|
+
old.exists? and @new.class_snapshots.all?{ |new|
|
40
34
|
old != new
|
41
35
|
}
|
42
36
|
}
|
43
37
|
end
|
44
38
|
|
39
|
+
def removed_class_names
|
40
|
+
removed_classes.map(&:class_name).sort
|
41
|
+
end
|
42
|
+
|
45
43
|
def new_classes
|
46
44
|
@new.class_snapshots.select{ |new|
|
47
45
|
new.exists? and @old.class_snapshots.all?{ |old|
|
@@ -49,5 +47,46 @@ module MaglevRecord
|
|
49
47
|
}
|
50
48
|
}
|
51
49
|
end
|
50
|
+
|
51
|
+
def new_class_names
|
52
|
+
new_classes.map(&:class_name).sort
|
53
|
+
end
|
54
|
+
|
55
|
+
def migration_string_list
|
56
|
+
if removed_classes.size == 1 and new_classes.size == 1
|
57
|
+
["rename_class #{removed_class_names.first
|
58
|
+
}, :#{new_class_names.first}"]
|
59
|
+
else
|
60
|
+
removed_class_names.map{ |class_name|
|
61
|
+
"delete_class #{class_name}"
|
62
|
+
} + new_class_names.map{ |class_name|
|
63
|
+
"#new class: #{class_name}"
|
64
|
+
}
|
65
|
+
end + changed_classes.map(&:migration_string_list).flatten
|
66
|
+
end
|
67
|
+
|
68
|
+
def migration_string(identation = 0)
|
69
|
+
" " * identation + migration_string_list.select{ |s| s.strip != ""}.join("\n" + " " * identation)
|
70
|
+
end
|
71
|
+
|
72
|
+
def nothing_changed?
|
73
|
+
removed_classes == [] and changed_classes == [] and new_classes == []
|
74
|
+
end
|
75
|
+
|
76
|
+
def [](class_or_class_name)
|
77
|
+
changed_classes.each{ |change|
|
78
|
+
return change if change.changed_class == class_or_class_name or
|
79
|
+
change.class_name == class_or_class_name
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def superclass_mismatch_classes
|
84
|
+
[]
|
85
|
+
end
|
86
|
+
|
87
|
+
def reversed
|
88
|
+
self.class.new(@new, @old)
|
89
|
+
end
|
90
|
+
|
52
91
|
end
|
53
92
|
end
|