maintain 0.2.1 → 0.2.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/VERSION +1 -1
- data/lib/maintain/backend/active_record.rb +1 -1
- data/lib/maintain/backend/data_mapper.rb +29 -0
- data/lib/maintain/backend.rb +41 -1
- data/lib/maintain.rb +8 -21
- data/maintain.gemspec +47 -18
- data/spec/active_record_spec.rb +39 -1
- data/spec/data_mapper_spec.rb +86 -87
- metadata +6 -5
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.2
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Maintain
|
2
|
+
module Backend
|
3
|
+
class DataMapper < Maintain::Backend::Base
|
4
|
+
def aggregate(maintainee, name, attribute, states)
|
5
|
+
# named_scope will handle the array of states as "IN" in SQL
|
6
|
+
state(maintainee, name, attribute, states)
|
7
|
+
end
|
8
|
+
|
9
|
+
def read(instance, attribute)
|
10
|
+
instance.attributes[attribute.to_s]
|
11
|
+
end
|
12
|
+
|
13
|
+
def state(maintainee, name, attribute, value)
|
14
|
+
conditions = {:conditions => {attribute => value}}
|
15
|
+
maintainee.class_eval <<-scope
|
16
|
+
def self.#{name}
|
17
|
+
all(#{conditions.inspect})
|
18
|
+
end
|
19
|
+
scope
|
20
|
+
end
|
21
|
+
|
22
|
+
def write(instance, attribute, value)
|
23
|
+
property = instance.send(:properties)[attribute]
|
24
|
+
instance.persisted_state = instance.persisted_state.set(property, value)
|
25
|
+
instance.persisted_state.get(property)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/maintain/backend.rb
CHANGED
@@ -3,8 +3,27 @@ require 'maintain/backend/base'
|
|
3
3
|
module Maintain
|
4
4
|
module Backend
|
5
5
|
class << self
|
6
|
+
def add(name, owner)
|
7
|
+
classes[name.to_sym] = owner
|
8
|
+
modules = owner.split('::')
|
9
|
+
if Object.const_defined?(modules.first) && owner = Object.const_get(modules.shift)
|
10
|
+
while modules.length > 0
|
11
|
+
owner = owner.const_get(modules.shift)
|
12
|
+
end
|
13
|
+
if owner.is_a? Module
|
14
|
+
owner.class_eval do
|
15
|
+
class << self
|
16
|
+
include Maintain
|
17
|
+
end
|
18
|
+
end
|
19
|
+
else
|
20
|
+
owner.extend Maintain
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
6
25
|
def build(back_end, maintainer)
|
7
|
-
back_end = back_end.split('_').map(&:capitalize).join('')
|
26
|
+
back_end = back_end.to_s.split('_').map(&:capitalize).join('')
|
8
27
|
if constants.include? back_end.to_s
|
9
28
|
const_get(back_end.to_sym).new
|
10
29
|
else
|
@@ -16,6 +35,10 @@ module Maintain
|
|
16
35
|
end
|
17
36
|
end
|
18
37
|
|
38
|
+
def classes
|
39
|
+
@classes ||= {}
|
40
|
+
end
|
41
|
+
|
19
42
|
def const_missing(constant)
|
20
43
|
underscore_constant = constant.to_s.dup
|
21
44
|
underscore_constant.gsub!(/::/, '/')
|
@@ -30,6 +53,23 @@ module Maintain
|
|
30
53
|
super
|
31
54
|
end
|
32
55
|
end
|
56
|
+
|
57
|
+
# Detect if we've loaded a backend for this class - that means if its ancestors or
|
58
|
+
# parent classes include any of our back-end classes.
|
59
|
+
def detect(owner)
|
60
|
+
ancestors = owner.ancestors.map(&:to_s)
|
61
|
+
# While owner does not refer to "Object"
|
62
|
+
while owner.superclass
|
63
|
+
ancestors.push(owner.to_s)
|
64
|
+
owner = owner.superclass
|
65
|
+
end
|
66
|
+
classes.each do |back_end, class_name|
|
67
|
+
if ancestors.include? class_name
|
68
|
+
return back_end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
nil
|
72
|
+
end
|
33
73
|
end
|
34
74
|
end
|
35
75
|
end
|
data/lib/maintain.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
$LOAD_PATH.unshift File.join(File.dirname(__FILE__))
|
3
|
+
require 'maintain/backend'
|
3
4
|
|
4
5
|
module Maintain
|
5
6
|
# We're not really interested in loading anything into memory if we don't need to,
|
6
7
|
# so Maintainer, Value, and the Value subclasses are ignored until they're needed.
|
7
8
|
autoload(:Maintainer, 'maintain/maintainer')
|
8
|
-
autoload(:Backend, 'maintain/backend')
|
9
9
|
autoload(:Value, 'maintain/value')
|
10
10
|
autoload(:BitmaskValue, 'maintain/bitmask_value')
|
11
11
|
autoload(:IntegerValue, 'maintain/integer_value')
|
@@ -31,17 +31,7 @@ module Maintain
|
|
31
31
|
# This method is aliased as `maintains` with the intention of allowing developers
|
32
32
|
# to code imperatively ("maintain, damn you!") or descriptively ("it maintains, man")
|
33
33
|
def maintain(attribute, options = {}, &block)
|
34
|
-
|
35
|
-
# TODO: Make this not suck
|
36
|
-
if defined?(ActiveRecord::Base)
|
37
|
-
active_record = self == ActiveRecord::Base
|
38
|
-
superclass = self
|
39
|
-
while !active_record && superclass.superclass
|
40
|
-
active_record = superclass == ActiveRecord::Base
|
41
|
-
superclass = superclass.superclass
|
42
|
-
end
|
43
|
-
options[:back_end] = 'active_record' if active_record
|
44
|
-
end
|
34
|
+
options[:back_end] ||= Maintain::Backend.detect(self)
|
45
35
|
|
46
36
|
# Create an instance of the maintainer class. It handles all of the state
|
47
37
|
# configuration, hooking, aggregation, named_scoping, etc.
|
@@ -67,22 +57,20 @@ module Maintain
|
|
67
57
|
|
68
58
|
# Allow the back end to write values in an ORM-specific way
|
69
59
|
if maintainer.back_end
|
70
|
-
maintainer.back_end.write(self, :#{attribute}, value)
|
60
|
+
maintainer.back_end.write(self, :#{attribute}, #{attribute}.value)
|
71
61
|
end
|
72
62
|
|
73
63
|
# Last but not least, run the enter hooks for the new value - cause that's how
|
74
64
|
# we do.
|
75
65
|
maintainer.hook(:enter, #{attribute}.name, self) if changed
|
66
|
+
else
|
67
|
+
@#{attribute} = value
|
76
68
|
end
|
77
69
|
end
|
78
70
|
|
79
71
|
def #{attribute}
|
80
72
|
if maintainer = self.class.maintainers[:#{attribute}]
|
81
|
-
|
82
|
-
@#{attribute}
|
83
|
-
else
|
84
|
-
@#{attribute} = maintainer.value(self)
|
85
|
-
end
|
73
|
+
@#{attribute} ||= maintainer.value(self)
|
86
74
|
else
|
87
75
|
@#{attribute}
|
88
76
|
end
|
@@ -107,6 +95,5 @@ module Maintain
|
|
107
95
|
end
|
108
96
|
end
|
109
97
|
|
110
|
-
|
111
|
-
|
112
|
-
end
|
98
|
+
Maintain::Backend.add(:active_record, 'ActiveRecord::Base')
|
99
|
+
Maintain::Backend.add(:data_mapper, 'DataMapper::Resource')
|
data/maintain.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{maintain}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Flip Sasser"]
|
12
|
-
s.date = %q{2011-02-
|
12
|
+
s.date = %q{2011-02-23}
|
13
13
|
s.description = %q{
|
14
14
|
Maintain is a simple state machine mixin for Ruby objects. It supports comparisons, bitmasks,
|
15
15
|
and hooks that really work. It can be used for multiple attributes and will always do its best to
|
@@ -20,30 +20,59 @@ Gem::Specification.new do |s|
|
|
20
20
|
"README.markdown"
|
21
21
|
]
|
22
22
|
s.files = [
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
23
|
+
".rspec",
|
24
|
+
"README.markdown",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"autotest/discover.rb",
|
28
|
+
"lib/maintain.rb",
|
29
|
+
"lib/maintain/backend.rb",
|
30
|
+
"lib/maintain/backend/active_record.rb",
|
31
|
+
"lib/maintain/backend/base.rb",
|
32
|
+
"lib/maintain/backend/data_mapper.rb",
|
33
|
+
"lib/maintain/bitmask_value.rb",
|
34
|
+
"lib/maintain/integer_value.rb",
|
35
|
+
"lib/maintain/maintainer.rb",
|
36
|
+
"lib/maintain/value.rb",
|
37
|
+
"maintain.gemspec",
|
38
|
+
"spec/active_record_spec.rb",
|
39
|
+
"spec/aggregates_spec.rb",
|
40
|
+
"spec/bitwise_spec.rb",
|
41
|
+
"spec/comparing_state_spec.rb",
|
42
|
+
"spec/data_mapper_spec.rb",
|
43
|
+
"spec/defining_states_spec.rb",
|
44
|
+
"spec/hooks_spec.rb",
|
45
|
+
"spec/integer_spec.rb",
|
46
|
+
"spec/maintain_spec.rb",
|
47
|
+
"spec/object_spec.rb",
|
48
|
+
"spec/proxy_spec.rb",
|
49
|
+
"spec/setting_state_spec.rb",
|
50
|
+
"spec/spec.opts"
|
34
51
|
]
|
35
52
|
s.homepage = %q{http://github.com/flipsasser/maintain}
|
36
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
37
53
|
s.require_paths = ["lib"]
|
38
|
-
s.rubygems_version = %q{1.3.
|
54
|
+
s.rubygems_version = %q{1.3.7}
|
39
55
|
s.summary = %q{A Ruby state machine that lets your code do the driving}
|
40
|
-
s.test_files =
|
56
|
+
s.test_files = [
|
57
|
+
"spec/active_record_spec.rb",
|
58
|
+
"spec/aggregates_spec.rb",
|
59
|
+
"spec/bitwise_spec.rb",
|
60
|
+
"spec/comparing_state_spec.rb",
|
61
|
+
"spec/data_mapper_spec.rb",
|
62
|
+
"spec/defining_states_spec.rb",
|
63
|
+
"spec/hooks_spec.rb",
|
64
|
+
"spec/integer_spec.rb",
|
65
|
+
"spec/maintain_spec.rb",
|
66
|
+
"spec/object_spec.rb",
|
67
|
+
"spec/proxy_spec.rb",
|
68
|
+
"spec/setting_state_spec.rb"
|
69
|
+
]
|
41
70
|
|
42
71
|
if s.respond_to? :specification_version then
|
43
72
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
44
73
|
s.specification_version = 3
|
45
74
|
|
46
|
-
if Gem::Version.new(Gem::
|
75
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
76
|
else
|
48
77
|
end
|
49
78
|
else
|
data/spec/active_record_spec.rb
CHANGED
@@ -27,6 +27,7 @@ if proceed
|
|
27
27
|
ActiveRecord::Schema.define do
|
28
28
|
create_table :active_maintain_tests, :force => true do |t|
|
29
29
|
t.string :status
|
30
|
+
t.integer :permissions
|
30
31
|
end
|
31
32
|
end
|
32
33
|
end
|
@@ -55,12 +56,49 @@ if proceed
|
|
55
56
|
ActiveMaintainTest.first.status.should == 'old'
|
56
57
|
end
|
57
58
|
|
59
|
+
it "should allow us to update statuses using update_attributes" do
|
60
|
+
active_maintain_test = ActiveMaintainTest.new
|
61
|
+
active_maintain_test.update_attributes(:status => :bar)
|
62
|
+
ActiveMaintainTest.first.status.should == :bar
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should allow us to update statuses using update_attribute" do
|
66
|
+
active_maintain_test = ActiveMaintainTest.new
|
67
|
+
active_maintain_test.update_attribute(:status, :bar)
|
68
|
+
ActiveMaintainTest.first.status.should == :bar
|
69
|
+
end
|
70
|
+
|
58
71
|
it "should return the correct name when told to" do
|
59
72
|
active_maintain_test = ActiveMaintainTest.create(:status => 'old')
|
60
73
|
ActiveMaintainTest.first.status.name.should == 'old'
|
61
74
|
end
|
62
75
|
end
|
63
76
|
|
77
|
+
describe "bitmasks" do
|
78
|
+
before :each do
|
79
|
+
ActiveMaintainTest.maintain :permissions, :bitmask => true do
|
80
|
+
state :add, 0
|
81
|
+
state :delete, 1
|
82
|
+
state :foo, 2
|
83
|
+
state :bar, 3
|
84
|
+
|
85
|
+
aggregate :everything, :as => [:new, :old, :foo, :bar]
|
86
|
+
aggregate :fakes, :as => [:foo, :bar]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should allow me to set a bitmask value" do
|
91
|
+
active_maintain_test = ActiveMaintainTest.create(:permissions => 'add')
|
92
|
+
ActiveMaintainTest.last.permissions.add?.should be_true
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should allow me to set multiple bitmask values" do
|
96
|
+
active_maintain_test = ActiveMaintainTest.create(:permissions => ['add', 'delete'])
|
97
|
+
ActiveMaintainTest.last.permissions.add?.should be_true
|
98
|
+
ActiveMaintainTest.last.permissions.delete?.should be_true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
64
102
|
describe "named_scopes" do
|
65
103
|
it "should create named_scopes for all states" do
|
66
104
|
ActiveMaintainTest.should respond_to(:old)
|
@@ -84,4 +122,4 @@ if proceed
|
|
84
122
|
|
85
123
|
end
|
86
124
|
end
|
87
|
-
end
|
125
|
+
end
|
data/spec/data_mapper_spec.rb
CHANGED
@@ -1,87 +1,86 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
# end
|
1
|
+
proceed = false
|
2
|
+
begin
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'datamapper'
|
5
|
+
require 'datamapper'
|
6
|
+
proceed = true
|
7
|
+
rescue Gem::LoadError, LoadError
|
8
|
+
puts 'Not testing DataMapper (unavailable)'
|
9
|
+
end
|
10
|
+
|
11
|
+
if proceed
|
12
|
+
# Use load to have it evaluate the DataMapper extension logic again, in the event
|
13
|
+
# that we've already done that with a previous test.
|
14
|
+
load 'lib/maintain.rb'
|
15
|
+
|
16
|
+
DataMapper.setup(:default, "sqlite3::memory:")
|
17
|
+
|
18
|
+
class ::DataMapperMaintainTest
|
19
|
+
include DataMapper::Resource
|
20
|
+
extend Maintain
|
21
|
+
|
22
|
+
property :id, Serial
|
23
|
+
property :status, String
|
24
|
+
|
25
|
+
maintain :status do
|
26
|
+
state :new, :default => true
|
27
|
+
state :old
|
28
|
+
state :foo
|
29
|
+
state :bar
|
30
|
+
aggregate :everything, :as => [:new, :old, :foo, :bar]
|
31
|
+
aggregate :fakes, :as => [:foo, :bar]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
DataMapper.auto_upgrade!
|
36
|
+
|
37
|
+
describe Maintain, "Datamapper::Resource" do
|
38
|
+
it "should automatically be extended" do
|
39
|
+
DataMapper::Resource.instance_methods.should include('maintain')
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "accessors" do
|
43
|
+
it "should default to 'new'" do
|
44
|
+
DataMapperMaintainTest.new.status.should == 'new'
|
45
|
+
DataMapperMaintainTest.new.status.should == :new
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should allow us to update its status to 'old'" do
|
49
|
+
active_maintain_test = DataMapperMaintainTest.new(:status => 'old')
|
50
|
+
active_maintain_test.status.should == 'old'
|
51
|
+
lambda {
|
52
|
+
active_maintain_test.save!
|
53
|
+
}.should_not raise_error
|
54
|
+
DataMapperMaintainTest.first.status.should == 'old'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return the correct name when told to" do
|
58
|
+
active_maintain_test = DataMapperMaintainTest.create(:status => 'old')
|
59
|
+
DataMapperMaintainTest.first.status.name.should == 'old'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "named_scopes" do
|
64
|
+
it "should create named_scopes for all states" do
|
65
|
+
DataMapperMaintainTest.should respond_to(:old)
|
66
|
+
DataMapperMaintainTest.old.should respond_to(:each)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should create named_scopes for all aggregates" do
|
70
|
+
DataMapperMaintainTest.should respond_to(:everything)
|
71
|
+
DataMapperMaintainTest.everything.should respond_to(:each)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should return the correct collections on aggregates" do
|
75
|
+
DataMapperMaintainTest.all.destroy!
|
76
|
+
one = DataMapperMaintainTest.create(:status => :foo)
|
77
|
+
two = DataMapperMaintainTest.create(:status => :bar)
|
78
|
+
three = DataMapperMaintainTest.create(:status => :new)
|
79
|
+
four = DataMapperMaintainTest.create(:status => :old)
|
80
|
+
DataMapperMaintainTest.fakes.should == [one, two]
|
81
|
+
DataMapperMaintainTest.everything.should == [one, two, three, four]
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maintain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 2
|
10
|
+
version: 0.2.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Flip Sasser
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-23 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- lib/maintain/backend.rb
|
38
38
|
- lib/maintain/backend/active_record.rb
|
39
39
|
- lib/maintain/backend/base.rb
|
40
|
+
- lib/maintain/backend/data_mapper.rb
|
40
41
|
- lib/maintain/bitmask_value.rb
|
41
42
|
- lib/maintain/integer_value.rb
|
42
43
|
- lib/maintain/maintainer.rb
|
@@ -46,6 +47,7 @@ files:
|
|
46
47
|
- spec/aggregates_spec.rb
|
47
48
|
- spec/bitwise_spec.rb
|
48
49
|
- spec/comparing_state_spec.rb
|
50
|
+
- spec/data_mapper_spec.rb
|
49
51
|
- spec/defining_states_spec.rb
|
50
52
|
- spec/hooks_spec.rb
|
51
53
|
- spec/integer_spec.rb
|
@@ -54,7 +56,6 @@ files:
|
|
54
56
|
- spec/proxy_spec.rb
|
55
57
|
- spec/setting_state_spec.rb
|
56
58
|
- spec/spec.opts
|
57
|
-
- spec/data_mapper_spec.rb
|
58
59
|
has_rdoc: true
|
59
60
|
homepage: http://github.com/flipsasser/maintain
|
60
61
|
licenses: []
|