maglevrecord 0.0.3

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.
@@ -0,0 +1,66 @@
1
+ require "maglev_record/persistence"
2
+ require "maglev_record/enumerable"
3
+ require "maglev_record/read_write"
4
+ require "rubygems"
5
+ require "active_support"
6
+ require "active_model"
7
+
8
+ module MaglevRecord
9
+ module Base
10
+ extend ActiveSupport::Concern
11
+ extend ActiveModel::Naming
12
+
13
+ @attributes = {}
14
+ included do
15
+ include ActiveModel
16
+ include ActiveModel::AttributeMethods
17
+ include ActiveModel::Conversion
18
+ include ActiveModel::Dirty
19
+ include ActiveModel::MassAssignmentSecurity
20
+ include ActiveModel::Validations
21
+ include MaglevRecord::Persistence
22
+ include MaglevRecord::Enumerable
23
+ include MaglevRecord::ReadWrite
24
+
25
+ self.maglev_persistable
26
+ ActiveSupport.maglev_persistable
27
+ ActiveSupport::HashWithIndifferentAccess.maglev_persistable
28
+ end
29
+
30
+ def initialize(*args)
31
+ if args.size == 1
32
+ args[0].each do |k, v|
33
+ self.send("#{k.to_s}=".to_sym, v)
34
+ end
35
+ end
36
+ end
37
+
38
+ def clear_dirty
39
+ @dirty = nil
40
+ end
41
+ def reset!
42
+ changed.each do |attr|
43
+ self.send "reset_#{attr}!".to_sym
44
+ end
45
+ clear_dirty
46
+ end
47
+
48
+ def attributes
49
+ @attributes ||= {}
50
+ end
51
+
52
+ module ClassMethods
53
+ def create(*args)
54
+ x = self.new(*args)
55
+ x
56
+ end
57
+
58
+ end
59
+
60
+ def to_key
61
+ key = self.__id__
62
+ [key] if key
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,35 @@
1
+ require "active_support"
2
+
3
+ module MaglevRecord
4
+ module Enumerable
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ include ::Enumerable
9
+
10
+ def each
11
+ self.object_pool.each_value do |el|
12
+ yield(el)
13
+ end
14
+ end
15
+
16
+ def size
17
+ self.object_pool.size
18
+ end
19
+
20
+ alias_method :length, :size
21
+
22
+ def find_by_objectid(id)
23
+ self.object_pool[id]
24
+ end
25
+
26
+ def all
27
+ self.object_pool.values
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
@@ -0,0 +1,15 @@
1
+ # Maglev.persistent do
2
+ # Object.remove_const(:NotSavedOnReset)
3
+ # end
4
+ # Maglev.commit_transaction
5
+
6
+ module MaglevRecord
7
+ Maglev.transient do
8
+ class ModelNotSavedOrReset
9
+ @instance = self.new
10
+ def self.new
11
+ @instance
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ require "active_support"
2
+
3
+ module MaglevRecord
4
+ module Persistence
5
+ extend ActiveSupport::Concern
6
+
7
+ def delete
8
+ self.class.delete(self)
9
+ end
10
+
11
+ def save!(options = {})
12
+ if options[:validate] == false or self.valid?
13
+ @previously_changed = changes
14
+ @changed_attributes.clear
15
+ self.instance_variable_set(:@errors, nil)
16
+ self.class.object_pool[self.object_id] = self
17
+ @dirty = nil
18
+ true
19
+ else
20
+ raise StandardError, "Model validation failed"
21
+ end
22
+ end
23
+
24
+ def save(options = {})
25
+ begin
26
+ self.save!(options)
27
+ rescue StandardError
28
+ false
29
+ end
30
+ end
31
+
32
+ def persisted?
33
+ !new_record?
34
+ end
35
+
36
+ def new_record?
37
+ !committed?
38
+ end
39
+
40
+ module ClassMethods
41
+ def object_pool
42
+ Maglev::PERSISTENT_ROOT[self.name.to_sym] ||= {}
43
+ end
44
+
45
+ def delete(*args)
46
+ if block_given? and args.size == 0
47
+ self.all.each do |m|
48
+ self.object_pool.delete(m.object_id) if yield(m)
49
+ end
50
+ elsif !block_given? and args.size > 0
51
+ args.each do |m|
52
+ self.object_pool.delete(m.object_id)
53
+ end
54
+ else
55
+ raise ArgumentError, "only block or arguments allowed"
56
+ end
57
+ end
58
+
59
+ def clear
60
+ self.object_pool.clear
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+
@@ -0,0 +1,41 @@
1
+ require "active_support"
2
+
3
+ module MaglevRecord
4
+ module ReadWrite
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def attr_reader(*attr_names)
9
+ attr_names.each do |attr_name|
10
+ define_attribute_method(attr_name)
11
+
12
+ generated_attribute_methods.module_eval <<-ATTRREADER, __FILE__, __LINE__ + 1
13
+ def #{attr_name}
14
+ attributes[:#{attr_name}]
15
+ end
16
+ ATTRREADER
17
+ end
18
+ end
19
+
20
+ def attr_writer(*attr_names)
21
+ attr_names.each do |attr_name|
22
+ define_attribute_method(attr_name)
23
+
24
+ generated_attribute_methods.module_eval <<-ATTRWRITER, __FILE__, __LINE__ + 1
25
+ def #{attr_name}=(new_value)
26
+ @dirty = ModelNotSavedOrReset.new
27
+ #{attr_name}_will_change! unless new_value == attributes[:#{attr_name}]
28
+ attributes[:#{attr_name}] = new_value
29
+ end
30
+ ATTRWRITER
31
+ end
32
+ end
33
+
34
+ def attr_accessor(*attr_names)
35
+ attr_reader *attr_names
36
+ attr_writer *attr_names
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,4 @@
1
+ require "rubygems"
2
+ require "maglev_record/model_not_saved_or_reset"
3
+ require "maglev_record/base"
4
+ require "maglev_record/persistence"
@@ -0,0 +1,19 @@
1
+ require "maglev_record"
2
+
3
+ class Book
4
+ include MaglevRecord::Base
5
+
6
+ attr_accessor :author, :title, :comments
7
+
8
+ validates :author, :presence => true
9
+ validates :title, :presence => true,
10
+ :length => { :minimum => 5 }
11
+
12
+ def to_s
13
+ title
14
+ end
15
+
16
+ def self.dummy
17
+ Book.new(:title => "Harry Potter and the Chamber of Secrets", :author => "Joanne K. Rowling")
18
+ end
19
+ end
data/test/lint.rb ADDED
@@ -0,0 +1,110 @@
1
+ module ActiveModel
2
+ module Lint
3
+ # == Active \Model \Lint \Tests
4
+ #
5
+ # You can test whether an object is compliant with the Active \Model API by
6
+ # including <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will
7
+ # include tests that tell you whether your object is fully compliant,
8
+ # or if not, which aspects of the API are not implemented.
9
+ #
10
+ # Note an object is not required to implement all APIs in order to work
11
+ # with Action Pack. This module only intends to provide guidance in case
12
+ # you want all features out of the box.
13
+ #
14
+ # These tests do not attempt to determine the semantic correctness of the
15
+ # returned values. For instance, you could implement <tt>valid?</tt> to
16
+ # always return true, and the tests would pass. It is up to you to ensure
17
+ # that the values are semantically meaningful.
18
+ #
19
+ # Objects you pass in are expected to return a compliant object from a call
20
+ # to <tt>to_model</tt>. It is perfectly fine for <tt>to_model</tt> to return
21
+ # +self+.
22
+ module Tests
23
+
24
+ # == Responds to <tt>to_key</tt>
25
+ #
26
+ # Returns an Enumerable of all (primary) key attributes
27
+ # or nil if <tt>model.persisted?</tt> is false. This is used by
28
+ # <tt>dom_id</tt> to generate unique ids for the object.
29
+ def test_to_key
30
+ assert model.respond_to?(:to_key), "The model should respond to to_key"
31
+ def model.persisted?() false end
32
+ assert model.to_key.nil?, "to_key should return nil when `persisted?` returns false"
33
+ end
34
+
35
+ # == Responds to <tt>to_param</tt>
36
+ #
37
+ # Returns a string representing the object's key suitable for use in URLs
38
+ # or +nil+ if <tt>model.persisted?</tt> is +false+.
39
+ #
40
+ # Implementers can decide to either raise an exception or provide a
41
+ # default in case the record uses a composite primary key. There are no
42
+ # tests for this behavior in lint because it doesn't make sense to force
43
+ # any of the possible implementation strategies on the implementer.
44
+ # However, if the resource is not persisted?, then <tt>to_param</tt>
45
+ # should always return +nil+.
46
+ def test_to_param
47
+ assert model.respond_to?(:to_param), "The model should respond to to_param"
48
+ def model.to_key() [1] end
49
+ def model.persisted?() false end
50
+ assert model.to_param.nil?, "to_param should return nil when `persisted?` returns false"
51
+ end
52
+
53
+ # == Responds to <tt>to_partial_path</tt>
54
+ #
55
+ # Returns a string giving a relative path. This is used for looking up
56
+ # partials. For example, a BlogPost model might return "blog_posts/blog_post"
57
+ def test_to_partial_path
58
+ assert model.respond_to?(:to_partial_path), "The model should respond to to_partial_path"
59
+ assert_kind_of String, model.to_partial_path
60
+ end
61
+
62
+ # == Responds to <tt>persisted?</tt>
63
+ #
64
+ # Returns a boolean that specifies whether the object has been persisted
65
+ # yet. This is used when calculating the URL for an object. If the object
66
+ # is not persisted, a form for that object, for instance, will route to
67
+ # the create action. If it is persisted, a form for the object will routes
68
+ # to the update action.
69
+ def test_persisted?
70
+ assert model.respond_to?(:persisted?), "The model should respond to persisted?"
71
+ assert_boolean model.persisted?, "persisted?"
72
+ end
73
+
74
+ # == \Naming
75
+ #
76
+ # Model.model_name must return a string with some convenience methods:
77
+ # <tt>:human</tt>, <tt>:singular</tt> and <tt>:plural</tt>. Check
78
+ # ActiveModel::Naming for more information.
79
+ def test_model_naming
80
+ assert model.class.respond_to?(:model_name), "The model should respond to model_name"
81
+ model_name = model.class.model_name
82
+ assert model_name.respond_to?(:to_str)
83
+ assert model_name.human.respond_to?(:to_str)
84
+ assert model_name.singular.respond_to?(:to_str)
85
+ assert model_name.plural.respond_to?(:to_str)
86
+ end
87
+
88
+ # == \Errors Testing
89
+ #
90
+ # Returns an object that implements [](attribute) defined which returns an
91
+ # Array of Strings that are the errors for the attribute in question.
92
+ # If localization is used, the Strings should be localized for the current
93
+ # locale. If no error is present, this method should return an empty Array.
94
+ def test_errors_aref
95
+ assert model.respond_to?(:errors), "The model should respond to errors"
96
+ assert model.errors[:hello].is_a?(Array), "errors#[] should return an Array"
97
+ end
98
+
99
+ private
100
+ def model
101
+ assert @model.respond_to?(:to_model), "The object should respond_to to_model"
102
+ @model.to_model
103
+ end
104
+
105
+ def assert_boolean(result, name)
106
+ assert result == true || result == false, "#{name} should be a boolean"
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,11 @@
1
+ require "test/unit"
2
+ require "maglev_record"
3
+ require "example_model"
4
+
5
+ class ActiveModelLikeInterfaceTest < Test::Unit::TestCase
6
+ include ActiveModel::Lint::Tests
7
+
8
+ def model
9
+ Book.dummy
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ # Maglev.persistent do
2
+ # Object.remove_const(:NotSavedOnReset)
3
+ # end
4
+ # Maglev.commit_transaction
5
+
6
+ # Maglev.transient do
7
+ # class ModelNotSavedOrReset
8
+ # end
9
+ # end
10
+
11
+ # Maglev::PERSISTENT_ROOT['tmp'] = NotSavedOnReset.new
12
+ # Maglev.commit_transaction
13
+
14
+ require 'rubygems'
15
+ require 'test/unit'
16
+
17
+ class DirtyObjectTest < Test::Unit::TestCase
18
+
19
+ def setup
20
+ Maglev.abort_transaction
21
+ @book = Book.dummy
22
+ @book.save
23
+ Maglev.commit_transaction
24
+ end
25
+
26
+ def test_no_save_or_reset_throws_error
27
+ @book.author = "Shakespeare"
28
+ assert_raise TransactionError do
29
+ Maglev.commit_transaction
30
+ end
31
+ end
32
+
33
+ def test_reset_throws_no_error
34
+ @book.author = "Shakespeare"
35
+ @book.reset!
36
+ assert_nothing_raised Exception do
37
+ Maglev.commit_transaction
38
+ end
39
+ assert_equal "Joanne K. Rowling", @book.author
40
+ end
41
+
42
+ def test_save_throws_no_error
43
+ @book.author = "Shakespeare"
44
+ @book.save
45
+ assert_nothing_raised Exception do
46
+ Maglev.commit_transaction
47
+ end
48
+ assert_equal @book.author, "Shakespeare"
49
+ end
50
+ end
@@ -0,0 +1,22 @@
1
+ #require 'bacon'
2
+ #require 'maglev_record'
3
+
4
+ #class ExampleStudent
5
+ # include Maglev::Base
6
+ #
7
+ # attr_accessible :name
8
+ #
9
+ # def initialize(name)
10
+ # name = name
11
+ # end
12
+ #end
13
+
14
+ #describe 'ExampleStudent' do
15
+ # let(:student) { ExampleStudent.new('Ferdinand') }
16
+ #
17
+ # it "should know its name" do
18
+ # subject.name.should equal('Ferdinand')
19
+ # end
20
+ #
21
+ #end
22
+
@@ -0,0 +1,45 @@
1
+ require "test/unit"
2
+ require "maglev_record"
3
+ require "example_model"
4
+
5
+ class MaglevSimplePersistanceTest < Test::Unit::TestCase
6
+
7
+ def run_with_new_transaction
8
+ Maglev.abort_transaction
9
+ yield
10
+ Maglev.commit_transaction
11
+ end
12
+
13
+ def test_model_is_persisted
14
+ run_with_new_transaction do
15
+ book = Book.new(:title => "The Magician's Guild", :author => "Trudi Canavan")
16
+ book.save
17
+ end
18
+
19
+ run_with_new_transaction do
20
+ assert_equal Book.find { |b| b.title == "The Magician's Guild"}.author, "Trudi Canavan"
21
+ end
22
+ end
23
+
24
+ def test_model_is_deleted
25
+ run_with_new_transaction do
26
+ book = Book.new(:title => "Harry Potter and the Philosopher's stone", :author => "Joanne K. Rowling")
27
+ book.save
28
+ end
29
+
30
+ run_with_new_transaction do
31
+ Book.find { |b| b.title == "Harry Potter and the Philosopher's stone"}.delete
32
+ end
33
+
34
+ run_with_new_transaction do
35
+ assert_nil Book.find { |b| b.title == "Harry Potter and the Philosopher's stone"}
36
+ end
37
+ end
38
+
39
+ def teardown
40
+ run_with_new_transaction do
41
+ Book.clear
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,50 @@
1
+ require "test/unit"
2
+ require "maglev_record"
3
+ require "example_model"
4
+
5
+ class QueryInterfaceTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ [
9
+ Book.new(:title => "Harry Potter and the Philosopher's stone", :author => "Joanne K. Rowling"),
10
+ Book.new(:title => "Harry Potter and the Chamber of Secrets", :author => "Joanne K. Rowling"),
11
+ Book.new(:title => "Harry Potter and the Prisoner of Azkaban", :author => "Joanne K. Rowling"),
12
+ Book.new(:title => "Harry Potter and the Goblet of Fire", :author => "Joanne K. Rowling"),
13
+ Book.new(:title => "Harry Potter and the Order of the Phoenix", :author => "Joanne K. Rowling"),
14
+ Book.new(:title => "Harry Potter and the Half-blood Prince", :author => "Joanne K. Rowling"),
15
+ Book.new(:title => "Harry Potter and the Deathly Hallows", :author => "Joanne K. Rowling"),
16
+ Book.new(:title => "The Magician's Guild", :author => "Trudi Canavan")
17
+ ].each do |book|
18
+ book.save
19
+ end
20
+ end
21
+
22
+ def teardown
23
+ Book.clear
24
+ end
25
+
26
+ def test_size_returns_correct_amount_of_books
27
+ assert_equal Book.size, 8
28
+ end
29
+
30
+ def test_clear_clears_the_database
31
+ assert Book.size > 0
32
+ Book.clear
33
+ assert Book.size == 0
34
+ end
35
+
36
+ def test_first_returns_the_first_book
37
+ assert Book.first.title.include? "Philosopher"
38
+ end
39
+
40
+ def test_normal_enumerable_methods_work
41
+ assert_equal 7, Book.count { |b| b.author == "Joanne K. Rowling" }
42
+ end
43
+
44
+ def test_work_on_real_objects
45
+ book = Book.first
46
+ book.author = "William Shakespeare"
47
+ assert_equal Book.first.author, "William Shakespeare"
48
+ end
49
+
50
+ end
@@ -0,0 +1,81 @@
1
+ require "test/unit"
2
+ require "maglev_record"
3
+ require "example_model"
4
+
5
+ class ValidationTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ [
9
+ Book.new(:title => "Harry Potter and the Philosopher's stone", :author => "Joanne K. Rowling"),
10
+ Book.new(:title => "Harry Potter and the Chamber of Secrets", :author => "Joanne K. Rowling")
11
+ ].each do |book|
12
+ book.save
13
+ end
14
+ end
15
+
16
+ def teardown
17
+ Book.clear
18
+ end
19
+
20
+ def test_reset_single_attribute
21
+ book = Book.find { |b| b.title == "Harry Potter and the Philosopher's stone" }
22
+ book.author = "J. R. R. Tolkien"
23
+ book.reset_author!
24
+ assert_equal book.author, "Joanne K. Rowling"
25
+ end
26
+
27
+ def test_reset_all_attributes
28
+ book = Book.find { |b| b.title == "Harry Potter and the Philosopher's stone" }
29
+ book.author = "J. R. R. Tolkien"
30
+ book.title = "The Lord of the Rings"
31
+ #book.reset!
32
+ #assert_equal book.author, "Joanne K. Rowling"
33
+ #assert_equal book.title, "Harry Potter and the Philosopher's stone"
34
+ end
35
+
36
+ def invalid_model
37
+ Book.new(:author => "J. R. R. Tolkien", :title => "LotR")
38
+ end
39
+
40
+ def test_validation_fails
41
+ book = invalid_model
42
+ assert !book.valid?
43
+ assert book.invalid?
44
+ end
45
+
46
+ def test_errors_not_empty
47
+ book = invalid_model
48
+ book.valid?
49
+ assert book.errors.count > 0
50
+ end
51
+
52
+ def test_validation_succeeds
53
+ book = Book.new(:author => "J. R. R. Tolkien", :title => "Harry Potter and the Philosopher's stone")
54
+ assert book.valid?
55
+ assert !book.invalid?
56
+ end
57
+
58
+ def test_save_excl_invalid_throws_error
59
+ book = invalid_model
60
+
61
+ @catch = false
62
+ begin
63
+ book.save!
64
+ rescue StandardError
65
+ @catch = true
66
+ end
67
+
68
+ assert @catch
69
+ end
70
+
71
+ def test_save_invalid_returns_false
72
+ book = invalid_model
73
+ assert !book.save
74
+ end
75
+
76
+ def test_save_skip_validation
77
+ book = invalid_model
78
+ assert book.save(:validate => false)
79
+ end
80
+ end
81
+
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: maglevrecord
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dimitri Korsch
9
+ - Kirstin Heidler
10
+ - Nicco Kunzmann
11
+ - Matthias Springer
12
+ - Stefan Bunk
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+ date: 2013-01-10 00:00:00.000000000 Z
17
+ dependencies: []
18
+ description: Library for using to MagLev to persist your data in a Rails app.
19
+ email: bp2012h1@hpi.uni-potsdam.de
20
+ executables: []
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - lib/maglev_record/model_not_saved_or_reset.rb
25
+ - lib/maglev_record/enumerable.rb
26
+ - lib/maglev_record/read_write.rb
27
+ - lib/maglev_record/persistence.rb
28
+ - lib/maglev_record/base.rb
29
+ - lib/maglev_record.rb
30
+ - test/example_model.rb
31
+ - test/test_validation.rb
32
+ - test/test_maglev_simple_persistance.rb
33
+ - test/test_maglev_record_base.rb
34
+ - test/lint.rb
35
+ - test/test_query_interface.rb
36
+ - test/test_dirty_object.rb
37
+ - test/test_active_model_like_interface.rb
38
+ homepage: https://github.com/knub/maglevrecord
39
+ licenses: []
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 1.8.11
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: MagLev persistence with an ActiveRecord-like interface!
62
+ test_files: []