maglevrecord 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []