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.
Files changed (109) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +0 -1
  3. data/README.md +22 -7
  4. data/Rakefile +2 -2
  5. data/install.sh +0 -1
  6. data/lib/maglev_record/base.rb +10 -1
  7. data/lib/maglev_record/enumerable.rb +6 -1
  8. data/lib/maglev_record/errors.rb +3 -0
  9. data/lib/maglev_record/maglev_record.rb +1 -1
  10. data/lib/maglev_record/maglev_support/concern.rb +2 -3
  11. data/lib/maglev_record/maglev_support/secure_password.rb +2 -3
  12. data/lib/maglev_record/migration/loader.rb +1 -1
  13. data/lib/maglev_record/migration/migration.rb +14 -0
  14. data/lib/maglev_record/migration/migrator.rb +22 -4
  15. data/lib/maglev_record/migration/operations.rb +58 -0
  16. data/lib/maglev_record/persistence.rb +12 -5
  17. data/lib/maglev_record/read_write.rb +38 -7
  18. data/lib/maglev_record/rooted_enumerable.rb +6 -1
  19. data/lib/maglev_record/rooted_persistence.rb +4 -0
  20. data/lib/maglev_record/sensible.rb +2 -2
  21. data/lib/maglev_record/snapshot/change.rb +54 -15
  22. data/lib/maglev_record/snapshot/class_change.rb +66 -0
  23. data/lib/maglev_record/snapshot/class_snapshot.rb +63 -0
  24. data/lib/maglev_record/snapshot/snapshot.rb +44 -38
  25. data/lib/maglev_record/snapshot/snapshotable.rb +81 -26
  26. data/lib/maglev_record/snapshot/superclass_mismatch_change.rb +143 -0
  27. data/lib/maglev_record/snapshot.rb +3 -2
  28. data/lib/maglev_record/validations.rb +49 -0
  29. data/lib/maglev_record.rb +3 -2
  30. data/lib/tasks/database.rake +61 -17
  31. data/test/automigration/rake_task_base.rb +57 -0
  32. data/test/automigration/test_auto.slow.rb +38 -0
  33. data/test/automigration/test_migration_string.rb +173 -0
  34. data/test/automigration/test_rake_task_preconditions.slow.rb +41 -0
  35. data/test/automigration/test_show.slow.rb +21 -0
  36. data/test/automigration/test_superclass_mismatch.rb +96 -0
  37. data/test/example_model.rb +7 -5
  38. data/test/migration/base_lectures.rb +30 -0
  39. data/test/migration/operation_setup.rb +66 -56
  40. data/test/migration/projects/automigration/.gitignore +15 -0
  41. data/test/migration/projects/automigration/Gemfile +44 -0
  42. data/test/migration/projects/automigration/Gemfile.lock +115 -0
  43. data/test/migration/projects/automigration/README.rdoc +261 -0
  44. data/test/migration/projects/automigration/Rakefile +17 -0
  45. data/test/migration/projects/automigration/app/assets/images/rails.png +0 -0
  46. data/test/migration/projects/automigration/app/assets/javascripts/application.js +15 -0
  47. data/test/migration/projects/automigration/app/assets/stylesheets/application.css +13 -0
  48. data/test/migration/projects/automigration/app/controllers/application_controller.rb +3 -0
  49. data/test/migration/projects/automigration/app/helpers/application_helper.rb +2 -0
  50. data/test/migration/projects/automigration/app/mailers/.gitkeep +0 -0
  51. data/test/migration/projects/automigration/app/models/.gitkeep +0 -0
  52. data/test/migration/projects/automigration/app/models/project_model.rb +8 -0
  53. data/test/migration/projects/automigration/app/views/layouts/application.html.erb +14 -0
  54. data/test/migration/projects/automigration/config/application.rb +62 -0
  55. data/test/migration/projects/automigration/config/boot.rb +6 -0
  56. data/test/migration/projects/automigration/config/database.yml +25 -0
  57. data/test/migration/projects/automigration/config/environment.rb +5 -0
  58. data/test/migration/projects/automigration/config/environments/development.rb +37 -0
  59. data/test/migration/projects/automigration/config/environments/production.rb +67 -0
  60. data/test/migration/projects/automigration/config/initializers/backtrace_silencers.rb +7 -0
  61. data/test/migration/projects/automigration/config/initializers/inflections.rb +15 -0
  62. data/test/migration/projects/automigration/config/initializers/mime_types.rb +5 -0
  63. data/test/migration/projects/automigration/config/initializers/secret_token.rb +7 -0
  64. data/test/migration/projects/automigration/config/initializers/session_store.rb +8 -0
  65. data/test/migration/projects/automigration/config/initializers/wrap_parameters.rb +14 -0
  66. data/test/migration/projects/automigration/config/locales/en.yml +5 -0
  67. data/test/migration/projects/automigration/config/routes.rb +58 -0
  68. data/test/migration/projects/automigration/config.ru +4 -0
  69. data/test/migration/projects/automigration/db/seeds.rb +7 -0
  70. data/test/migration/projects/automigration/lib/assets/.gitkeep +0 -0
  71. data/test/migration/projects/automigration/lib/tasks/.gitkeep +0 -0
  72. data/test/migration/projects/automigration/log/.gitkeep +0 -0
  73. data/test/migration/projects/automigration/public/404.html +26 -0
  74. data/test/migration/projects/automigration/public/422.html +26 -0
  75. data/test/migration/projects/automigration/public/500.html +25 -0
  76. data/test/migration/projects/automigration/public/favicon.ico +0 -0
  77. data/test/migration/projects/automigration/public/index.html +241 -0
  78. data/test/migration/projects/automigration/public/robots.txt +5 -0
  79. data/test/migration/projects/automigration/script/rails +6 -0
  80. data/test/migration/projects/project2/Rakefile +2 -2
  81. data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.31.38.rb +1 -1
  82. data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.31.52.rb +1 -1
  83. data/test/migration/projects/project2/migrations/migration_2013-04-Apr-23_17.32.07.rb +1 -1
  84. data/test/migration/test_change_superclass.rb +111 -0
  85. data/test/migration/test_loader.rb +6 -0
  86. data/test/migration/test_project.rb +1 -29
  87. data/test/migration/test_project1.slow.rb +1 -0
  88. data/test/migration/test_project2.slow.rb +7 -0
  89. data/test/migration/test_remove.rb +123 -2
  90. data/test/migration/todo.txt +1 -1
  91. data/test/more_asserts.rb +1 -1
  92. data/test/snapshot/test_attributes.rb +33 -0
  93. data/test/snapshot/{test_snapshot_attributes.slow.rb → test_attributes.slow.rb} +3 -5
  94. data/test/snapshot/test_classes.rb +32 -0
  95. data/test/snapshot/{test_snapshot_classes.slow.rb → test_classes.slow.rb} +1 -1
  96. data/test/snapshot/test_from_file_system.rb +113 -0
  97. data/test/snapshot/test_methods.rb +136 -0
  98. data/test/snapshot/test_methods.slow.rb +67 -0
  99. data/test/snapshot/test_reset.rb +68 -0
  100. data/test/snapshot/test_snapshot.rb +41 -75
  101. data/test/snapshot/test_snapshot.slow.rb +98 -0
  102. data/test/snapshot/test_snapshotable.rb +0 -1
  103. data/test/temp_dir_test.rb +40 -0
  104. data/test/test_active_model_like_interface.rb +4 -1
  105. data/test/test_model_timestamps.rb +13 -5
  106. data/test/test_query_interface.rb +10 -0
  107. data/test/test_sensibles.rb +18 -10
  108. data/test/test_validation.rb +2 -12
  109. metadata +64 -5
data/.gitignore CHANGED
@@ -33,3 +33,10 @@ gem_*_code.log
33
33
 
34
34
  /caller_content.rb
35
35
  /module_content.rb
36
+
37
+ # ignore files for presentation no 8
38
+ /a.rb
39
+ /b.rb
40
+ /snapshot_test.rb
41
+ /test3.rb
42
+
data/.travis.yml CHANGED
@@ -10,7 +10,6 @@ before_script:
10
10
  - "gem uninstall -x -i /home/travis/.rvm/gems/ruby-1.9.3-p327@global bundler"
11
11
  - "maglev-gem install bundler"
12
12
  - "bundle install"
13
- - "gem install maglevrecord"
14
13
  script:
15
14
  - "bundle exec rake testslow"
16
15
  - "bundle exec rake testslow"
data/README.md CHANGED
@@ -1,13 +1,15 @@
1
- # MagLevRecord - a model interface for Rails
1
+ # MagLevRecord - a model interface for Rails
2
+ [![Build Status master](https://travis-ci.org/knub/maglevrecord.png?branch=master)](https://travis-ci.org/knub/maglevrecord)
3
+ [![Code Climate](https://codeclimate.com/github/knub/maglevrecord.png)](https://codeclimate.com/github/knub/maglevrecord)
2
4
 
3
- master [![Build Status master](https://travis-ci.org/knub/maglevrecord.png?branch=master)](https://travis-ci.org/knub/maglevrecord)
4
- develop [![Build Status develop](https://travis-ci.org/knub/maglevrecord.png?branch=develop)](https://travis-ci.org/knub/maglevrecord)
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 is intended to replace ActiveRecord::Base when using MagLev. It is not ready for production use, but feel free to play around with it.
9
+ This gem offers all those features and bundles them in a comfortable way.
7
10
 
8
- ## Installation
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
- Classes which you wish to persist have to include ```MaglevRecord::Base``` or ```MaglevRecord::RootedBase```. You can still inherit from whatever base class you want.
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/**/test*.rb'] - FileList['test/**/test*.slow.rb']
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/**/test*.rb']
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))
@@ -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
@@ -7,4 +7,7 @@ module MaglevRecord
7
7
 
8
8
  class IrreversibleMigration < Error
9
9
  end
10
+
11
+ class NoMigrationReadError < Error
12
+ end
10
13
  end
@@ -1,5 +1,5 @@
1
1
  module MaglevRecord
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  PERSISTENT_ROOT_KEY = :MaglevRecord
4
4
 
5
5
  def self.save
@@ -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
- # TODO: No validations so far
8
- # validates_confirmation_of :password
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
- # TODO: Check class of migration is really migration!
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] ||= SortedSet.new
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 = @migration_list.reject do |mig|
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
- @created_at_timestamp = Time.now
12
+ created
13
13
  end
14
14
 
15
15
  def created_at
16
16
  @created_at_timestamp
17
17
  end
18
- def created_at=(timestamp)
19
- @created_at_timestamp = 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
- attr_readers << attr_name
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
@@ -1,6 +1,11 @@
1
1
  module MaglevRecord
2
2
  module RootedEnumerable
3
3
  module ClassMethods
4
+ def first
5
+ each{ |model|
6
+ return model
7
+ }
8
+ end
4
9
  def all
5
10
  object_pool.values
6
11
  end
@@ -22,4 +27,4 @@ module MaglevRecord
22
27
  end
23
28
  end
24
29
  end
25
- end
30
+ 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
- class ClassChange
5
- def initialize(old, new)
6
- @old = old
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
- @new.class_snapshots.select{ |new|
39
- not new.exists? and @old.class_snapshots.all?{ |old|
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