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
@@ -0,0 +1,66 @@
1
+ module MaglevRecord
2
+
3
+ #
4
+ # Change of a class between two class snapshots
5
+ #
6
+ class ClassChange
7
+ def initialize(old, new)
8
+ @old = old
9
+ @new = new
10
+ end
11
+
12
+ def new_attributes
13
+ (@new.attributes - @old.attributes).sort
14
+ end
15
+
16
+ def removed_attributes
17
+ (@old.attributes - @new.attributes).sort
18
+ end
19
+
20
+ def class_name
21
+ @old.class_name
22
+ end
23
+
24
+ def changed_class
25
+ @old.snapshot_class
26
+ end
27
+
28
+ def migration_string_list
29
+ if removed_attributes.size == 1 and new_attributes.size == 1
30
+ from_attr = removed_attributes.first
31
+ to_attr = new_attributes.first
32
+ ["#{class_name}.rename_attribute(:#{from_attr}, :#{to_attr})"]
33
+ else
34
+ removed_attributes.map{ |attr|
35
+ "#{class_name}.delete_attribute(:#{attr})"
36
+ } + new_attributes.map{ |attr|
37
+ "#new accessor :#{attr} of #{class_name}"
38
+ }
39
+ end + new_class_methods.map{ |cm|
40
+ "#new class method: #{class_name}.#{cm.to_s}"
41
+ } + new_instance_methods.map{ |im|
42
+ "#new instance method: #{class_name}.new.#{im.to_s}"
43
+ } + removed_class_methods.map{ |cm|
44
+ "#{class_name}.remove_class_method :#{cm}"
45
+ } + removed_instance_methods.map{ |im|
46
+ "#{class_name}.remove_instance_method :#{im}"
47
+ }
48
+ end
49
+
50
+ def new_instance_methods
51
+ (@new.instance_methods - @old.instance_methods).sort
52
+ end
53
+
54
+ def removed_instance_methods
55
+ (@old.instance_methods - @new.instance_methods).sort
56
+ end
57
+
58
+ def new_class_methods
59
+ (@new.class_methods - @old.class_methods).sort
60
+ end
61
+
62
+ def removed_class_methods
63
+ (@old.class_methods - @new.class_methods).sort
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,63 @@
1
+ require "maglev_record/snapshot/class_change.rb"
2
+
3
+ module MaglevRecord
4
+
5
+ class ClassSnapshot
6
+ def initialize(cls)
7
+ cls.redo_include_and_extend
8
+ @snapshot_class = cls
9
+ @attributes = cls.snapshot_attributes if cls.respond_to? :snapshot_attributes
10
+ @files = cls.file_paths
11
+ @exists = cls.has_definitions?
12
+ @class_methods = cls.snapshot_class_methods
13
+ @instance_methods = cls.snapshot_instance_methods
14
+ end
15
+
16
+ def exists?
17
+ @exists
18
+ end
19
+
20
+ def ==(other)
21
+ self.snapshot_class == other.snapshot_class \
22
+ and self.exists? == other.exists?
23
+ end
24
+
25
+ alias :eql? :==
26
+
27
+ def <=>(other)
28
+ class_name <=> other.class_name
29
+ end
30
+
31
+ def snapshot_class
32
+ @snapshot_class
33
+ end
34
+
35
+ def changes_since(older)
36
+ return nil unless changed_since?(older)
37
+ ClassChange.new(older, self)
38
+ end
39
+
40
+ def changed_since?(older)
41
+ attributes != older.attributes or
42
+ instance_methods != older.instance_methods or
43
+ class_methods != older.class_methods
44
+ end
45
+
46
+ def attributes
47
+ Array.new(@attributes || []).sort.uniq
48
+ end
49
+
50
+ def class_name
51
+ @snapshot_class.name
52
+ end
53
+
54
+ def class_methods
55
+ Array.new(@class_methods)
56
+ end
57
+
58
+ def instance_methods
59
+ @instance_methods
60
+ end
61
+ end
62
+ end
63
+
@@ -1,67 +1,73 @@
1
+ require "maglev_record/snapshot/snapshotable"
2
+ require "maglev_record/snapshot/class_snapshot"
1
3
  require "maglev_record/snapshot/change"
4
+ require "maglev_record/snapshot/superclass_mismatch_change"
2
5
 
3
6
  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
7
 
12
- def exists?
13
- @exists
14
- end
8
+ class Snapshot
15
9
 
16
- def ==(other)
17
- self.snapshot_class == other.snapshot_class \
18
- and self.exists? == other.exists?
10
+ def for_class(cls)
11
+ ClassSnapshot.new(cls)
19
12
  end
20
13
 
21
- alias :eql? :==
22
-
23
- def snapshot_class
24
- @snapshot_class
14
+ def initialize(classes = Snapshotable.snapshotable_classes)
15
+ @class_snapshots = classes.map{ |cls|
16
+ for_class cls
17
+ }
25
18
  end
26
19
 
27
20
  def changes_since(older)
28
- return nil unless changed_since?(older)
29
- ClassChange.new(older, self)
21
+ Change.new(older, self)
30
22
  end
31
23
 
32
- def changed_since?(older)
33
- attr_readers != older.attr_readers
24
+ def class_snapshots
25
+ Array.new(@class_snapshots)
34
26
  end
35
27
 
36
- def attr_readers
37
- @attr_readers
28
+ def snapshot_classes
29
+ class_snapshots.map(&:snapshot_class)
38
30
  end
39
31
 
40
- def class_name
41
- @snapshot_class.name
32
+ def class_names
33
+ class_snapshots.map(&:class_name).sort
42
34
  end
43
- end
44
35
 
45
- class Snapshot
46
-
47
- def for_class(cls)
48
- ClassSnapshot.new(cls)
36
+ def [](cls)
37
+ class_snapshots.each{ |snap|
38
+ return snap if snap.snapshot_class == cls
39
+ }
49
40
  end
50
41
 
51
- def initialize
52
- @class_snapshots = Snapshotable.snapshotable_classes.map{ |cls|
53
- for_class cls
42
+ def self.with_files(file_paths = [], classes = Snapshotable.snapshotable_classes)
43
+ class_files = classes.map(&:file_paths).flatten.uniq
44
+ restore_state = classes.map(&:reset)
45
+ begin
46
+ (file_paths + class_files).uniq.each{ |file_path|
47
+ begin
48
+ Kernel.load file_path if File.exist? file_path
49
+ rescue TypeError => e
50
+ class_name = e.message[/superclass mismatch for( class)? (\S*)$/, 2]
51
+ raise e if class_name.nil? # TODO: test
52
+ raise e unless Object.const_defined? class_name # TODO: test
53
+ cls = Object.const_get class_name # TODO: rescue exceptions
54
+ return SuperclassMismatchChange.new(cls, file_path)
55
+ end
54
56
  }
57
+ else
58
+ return new
59
+ ensure
60
+ restore_state.map(&:call)
61
+ end
55
62
  end
56
63
 
57
- def changes_since(older)
58
- Change.new(older, self)
64
+ def new_with_files(file_paths = [])
65
+ self.class.with_files(file_paths)
59
66
  end
60
67
 
61
- def class_snapshots
62
- Array.new(@class_snapshots)
68
+ def changes_in_files(file_paths = [])
69
+ return new_with_files(file_paths).changes_since(self)
63
70
  end
64
-
65
71
  end
66
72
  end
67
73
 
@@ -1,22 +1,9 @@
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
1
+ require "maglev_record/maglev_support/concern"
17
2
 
18
3
  module MaglevRecord
19
4
  module Snapshotable
5
+ extend MaglevSupport::Concern
6
+
20
7
  def self.snapshotable_classes
21
8
  classes = []
22
9
  Object.constants.each { |constant|
@@ -32,10 +19,6 @@ module MaglevRecord
32
19
 
33
20
  module ClassMethods
34
21
 
35
- def self.extended(base)
36
- base.exist! if base.respond_to? :exist!
37
- end
38
-
39
22
  def file_paths
40
23
  (self.instance_methods(false).map { |m|
41
24
  self.instance_method(m).source_location.first
@@ -45,13 +28,85 @@ module MaglevRecord
45
28
  end
46
29
 
47
30
  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?
31
+ # In nested transaction this error occurs:
32
+ # Error 2101, objId i52279553 does not exist, during transaction boundary
33
+ fp = file_paths
34
+ without_methods do
35
+ fp.each{ |file_path|
36
+ Kernel.load file_path if File.file? file_path
37
+ }
38
+ return !file_paths.empty?
39
+ end
40
+ end
41
+
42
+ def without_methods
43
+ return unless block_given?
44
+ memento = reset
45
+ begin
46
+ yield
47
+ ensure
48
+ memento.call
49
+ end
50
+ end
51
+
52
+ def class_methods_not_to_snapshot
53
+ @class_methods_not_to_reset ||= []
54
+ # hackady hack!
55
+ # welcome to the big ball of mud and the
56
+ # "I do not know what goes on after hours trying"-architecture
57
+ @class_methods_not_to_reset << "_validators"
58
+ @class_methods_not_to_reset << "_validators="
59
+ @class_methods_not_to_reset << "_validators?"
60
+ #@class_methods_not_to_reset << "method_missing"
61
+ @class_methods_not_to_reset << methods(false).select{|m| m.include? "callback" }
62
+ @class_methods_not_to_reset.flatten!
63
+ @class_methods_not_to_reset.map!(&:to_s)
64
+ @class_methods_not_to_reset.uniq!
65
+ @class_methods_not_to_reset
66
+ end
67
+
68
+ def snapshot_class_methods
69
+ methods(false) - class_methods_not_to_snapshot
70
+ end
71
+
72
+ def snapshot_instance_methods
73
+ instance_methods(false).reject{|m| m.include? 'callback' or m.include? 'valid'}
74
+ end
75
+
76
+ def class_methods_to_reset
77
+ snapshot_class_methods
78
+ end
79
+
80
+ def instance_methods_to_reset
81
+ snapshot_instance_methods
82
+ end
83
+
84
+ #
85
+ # resets the class to no methods
86
+ # returns a memento proc that can be called to restore the old state
87
+ #
88
+ def reset
89
+ _instance_methods = instance_methods_to_reset.map { |m|
90
+ meth = instance_method m
91
+ remove_method m
92
+ meth
93
+ }
94
+ _class_methods = class_methods_to_reset.map { |m|
95
+ meth = method m
96
+ singleton_class.remove_method m
97
+ meth
98
+ }
99
+ return Proc.new {
100
+ instance_methods_to_reset.each { |m| remove_method m }
101
+ class_methods_to_reset.each{ |m| singleton_class.remove_method m }
102
+ _instance_methods.each{|m|
103
+ define_method m.name, m
104
+ }
105
+ _class_methods.each{|m|
106
+ singleton_class.define_method m.name, m
107
+ }
108
+ self
53
109
  }
54
- exists?
55
110
  end
56
111
  end
57
112
  end
@@ -0,0 +1,143 @@
1
+
2
+ class ClassWithMismatchNotFound
3
+ def name
4
+ "<fill in the name of the new superclass here>"
5
+ end
6
+ end
7
+
8
+ module MaglevRecord
9
+ class SuperclassMismatchChangeBase
10
+ "new_class_names new_classes
11
+ removed_class_names removed_classes changed_classes changed_class_names
12
+ ".split.each do |name|
13
+ define_method(name){ [] }
14
+ end
15
+
16
+ def nothing_changed?
17
+ false
18
+ end
19
+
20
+ def superclass_mismatch_classes
21
+ [self]
22
+ end
23
+
24
+ def superclass_mismatch_class_names
25
+ superclass_mismatch_classes.map(&:class_name)
26
+ end
27
+
28
+ def changes_since(snapshot)
29
+ self
30
+ end
31
+
32
+ end
33
+
34
+ class SuperclassMismatchChange < SuperclassMismatchChangeBase
35
+ def initialize(cls, file_path)
36
+ @cls = cls
37
+ @file_path = file_path
38
+ end
39
+
40
+ def file_path
41
+ @file_path
42
+ end
43
+
44
+ def migration_string(identation = 0)
45
+ " " * identation + [
46
+ "# TypeError: superclass mismatch for #{class_name}",
47
+ "# in #{file_path}",
48
+ "#{class_name}.change_superclass_to #{new_superclass.name}"
49
+ ].join("\n" + " " * identation)
50
+ end
51
+
52
+ def determine_new_superclass
53
+ # 1. replace the actual class by a new one
54
+ # 2. inherit
55
+ # 3. get the superclass
56
+ # 4. restore the class
57
+ constant_name = mismatching_class.name
58
+ class_to_replace = nil # change the scope
59
+ Maglev.persistent do
60
+ begin
61
+ class_to_replace = Object.remove_const constant_name
62
+ rescue NameError
63
+ # negative path 1 TODO: test
64
+ return ClassWithMismatchNotFound.new
65
+ else
66
+ if class_to_replace != mismatching_class
67
+ # negative path 2 TODO: test
68
+ Object.const_set constant_name, class_to_replace
69
+ return ClassWithMismatchNotFound.new
70
+ end
71
+ end
72
+ end
73
+ begin
74
+ Kernel.load file_path
75
+ cls = Object.const_get constant_name
76
+ return cls.superclass
77
+ ensure
78
+ Object.const_set constant_name, class_to_replace
79
+ end
80
+ end
81
+
82
+ def new_superclass
83
+ @new_super_class = determine_new_superclass if @new_super_class.nil?
84
+ @new_super_class
85
+ end
86
+
87
+ # methods for the single change
88
+
89
+ def class_name
90
+ mismatching_class.name
91
+ end
92
+
93
+ def mismatching_class
94
+ @cls
95
+ end
96
+
97
+ # reverse
98
+
99
+ def reversed
100
+ ReversedSuperclassMismatchChange.new(self)
101
+ end
102
+ end
103
+
104
+ class ReversedSuperclassMismatchChange < SuperclassMismatchChangeBase
105
+ # TODO: test
106
+ def initialize(superclass_mismatch_change)
107
+ @superclass_mismatch_change = superclass_mismatch_change
108
+ end
109
+
110
+ def superclass_mismatch_change
111
+ @superclass_mismatch_change
112
+ end
113
+
114
+ def reversed
115
+ superclass_mismatch_change
116
+ end
117
+
118
+ def mismatching_class
119
+ superclass_mismatch_change.mismatching_class
120
+ end
121
+
122
+ def class_name
123
+ superclass_mismatch_change.mismatching_class
124
+ end
125
+
126
+ def file_path
127
+ superclass_mismatch_change.file_path
128
+ end
129
+
130
+ def old_superclass
131
+ mismatching_class.superclass
132
+ end
133
+
134
+ def migration_string(identation = 0)
135
+ " " * identation + [
136
+ "# TypeError: superclass mismatch for #{class_name}",
137
+ "# in #{file_path}",
138
+ "#{class_name}.change_superclass_to #{old_superclass.name}"
139
+ ].join("\n" + " " * identation)
140
+ end
141
+
142
+ end
143
+ end
@@ -1,5 +1,6 @@
1
1
  require "maglev_record/snapshot/snapshotable"
2
2
  require "maglev_record/snapshot/change"
3
+ require "maglev_record/snapshot/class_change"
4
+ require "maglev_record/snapshot/class_snapshot"
3
5
  require "maglev_record/snapshot/snapshot"
4
-
5
-
6
+ require "maglev_record/snapshot/superclass_mismatch_change"
@@ -0,0 +1,49 @@
1
+ module MaglevRecord
2
+ module Validations
3
+ def self.included(base)
4
+ base.extend(self::ClassMethods) if self.constants.include? 'ClassMethods'
5
+ end
6
+
7
+ def method_missing(symbol, *args)
8
+ self.class.create_validations
9
+ if self.respond_to?(symbol)
10
+ send(symbol, *args)
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ def method_missing(symbol, *args)
19
+ super unless symbol.to_s.include? "valid"
20
+
21
+ @validates_options ||= Hash.new
22
+ @validates_options[symbol] ||= []
23
+ @validates_options[symbol] << args
24
+ end
25
+
26
+ def create_validations
27
+ return if not self.maglev_persistable? or @validates_options.nil?
28
+
29
+ self.include MaglevSupport.constantize("ActiveModel::Validations")
30
+ @validates_options.each do |symbol, args_list|
31
+ args_list.each do |args|
32
+ self.send(symbol, *args)
33
+ end
34
+ end
35
+ @validates_options = nil
36
+ end
37
+
38
+ def reset
39
+ _validates_options = @validates_options
40
+ @validates_options = nil
41
+ reset_proc = super
42
+ return Proc.new {
43
+ reset_proc.call
44
+ @validates_options = _validates_options
45
+ }
46
+ end
47
+ end
48
+ end
49
+ end
data/lib/maglev_record.rb CHANGED
@@ -17,7 +17,6 @@ if defined? MaglevRecord::VERSION
17
17
  end
18
18
  MaglevRecord::Migration.redo_include_and_extend
19
19
  else
20
- puts "IT IS NOT DEFINED"
21
20
  # require "maglev_record/tools"
22
21
  require "maglev_record/maglev_record"
23
22
 
@@ -29,6 +28,7 @@ else
29
28
  require "maglev_record/errors"
30
29
  require "maglev_record/integration"
31
30
  require "maglev_record/persistence"
31
+ require "maglev_record/validations"
32
32
  require "maglev_record/read_write"
33
33
  require "maglev_record/rooted_persistence"
34
34
  require "maglev_record/migration"
@@ -54,7 +54,8 @@ else
54
54
  mod.maglev_record_persistable
55
55
  end
56
56
  end
57
+ ActiveModel::Errors.maglev_nil_references
58
+ Maglev.commit_transaction
57
59
  end
58
60
 
59
61
  ActiveModel::Errors.maglev_nil_references
60
- Maglev.commit_transaction
@@ -1,9 +1,9 @@
1
- require "maglev_record/migration"
2
- require "time"
1
+ require "maglev_record"
3
2
  require "logger"
4
3
  require "fileutils"
5
4
 
6
- MIGRATION_FOLDER = "migrations"
5
+ MIGRATION_FOLDER = "./migrations"
6
+ MODEL_FILES = Array.new(Dir.glob("./app/models/*.rb"))
7
7
 
8
8
  desc "transform the maglev database"
9
9
  namespace :migrate do
@@ -15,24 +15,68 @@ namespace :migrate do
15
15
  end
16
16
 
17
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)
18
+ task :up => [:setup] do
19
+ migrator = MaglevRecord::Migrator.for_directory(MIGRATION_FOLDER)
20
+ migrator.up(Logger.new(STDOUT))
21
+ Rake::Task['migrate:load_all_models'].execute
22
+ Maglev::PERSISTENT_ROOT[:last_snapshot] = MaglevRecord::Snapshot.new
23
+ Maglev.commit_transaction
24
+ end
25
+
26
+ desc "show which migrations would be done by up"
27
+ task :up? => :setup do
28
+ # TODO: test
29
+ migrator = MaglevRecord::Migrator.for_directory(MIGRATION_FOLDER)
30
+ migrator.up?(Logger.new(STDOUT))
24
31
  end
25
32
 
26
33
  desc "create a new migration in the migration folder"
27
34
  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}"
35
+ MaglevRecord::Migration.write_to_file(MIGRATION_FOLDER,
36
+ 'fill in description here')
36
37
  end
38
+
39
+ desc "create a migration file for the changes shown by migrate:auto?"
40
+ task :auto => :setup do
41
+ last_snapshot = Maglev::PERSISTENT_ROOT[:last_snapshot]
42
+ if last_snapshot.nil?
43
+ puts "rake migrate:up has to be done first"
44
+ break
45
+ end
46
+ changes = last_snapshot.changes_in_files(MODEL_FILES)
47
+ if changes.nothing_changed?
48
+ puts "# no changes"
49
+ break
50
+ end
51
+ upcode = changes.migration_string(4)
52
+ downcode = changes.reversed.migration_string(4)
53
+ file_name = MaglevRecord::Migration.write_to_file(MIGRATION_FOLDER,
54
+ 'fill in description here',
55
+ upcode,
56
+ downcode)
57
+ puts file_name
58
+ end
59
+
60
+ desc "show the changes since the last migrate:auto or migrate:up"
61
+ task :auto? do
62
+ last_snapshot = Maglev::PERSISTENT_ROOT[:last_snapshot]
63
+ if last_snapshot.nil?
64
+ puts "rake migrate:up has to be done first"
65
+ break
66
+ end
67
+ changes = last_snapshot.changes_in_files(MODEL_FILES)
68
+ if changes.nothing_changed?
69
+ puts "# no changes"
70
+ else
71
+ puts changes.migration_string
72
+ end
73
+ end
74
+
75
+ task :load_all_models do
76
+ MODEL_FILES.each do |model_file_path|
77
+ load model_file_path
78
+ end
79
+ end
80
+
37
81
  end
38
82