activeobject 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGE +10 -0
- data/Interface_desc +21 -0
- data/MIT-LICENSE +20 -0
- data/README +72 -0
- data/Rakefile.rb +9 -0
- data/active-object.gemspec +50 -0
- data/examples/account.rb +69 -0
- data/examples/data.tch +0 -0
- data/examples/light_cloud.yml +18 -0
- data/examples/test.rb +3 -0
- data/examples/user.rb +112 -0
- data/init.rb +4 -0
- data/lib/active-object.rb +23 -0
- data/lib/active_object/adapters/light_cloud.rb +40 -0
- data/lib/active_object/adapters/tokyo_cabinet.rb +48 -0
- data/lib/active_object/adapters/tokyo_tyrant.rb +14 -0
- data/lib/active_object/associations.rb +200 -0
- data/lib/active_object/base.rb +415 -0
- data/lib/active_object/callbacks.rb +180 -0
- data/lib/active_object/observer.rb +180 -0
- data/lib/active_object/serialization.rb +99 -0
- data/lib/active_object/serializers/json_serializer.rb +75 -0
- data/lib/active_object/serializers/xml_serializer.rb +325 -0
- data/lib/active_object/validations.rb +687 -0
- data/lib/active_support/callbacks.rb +303 -0
- data/lib/active_support/core_ext/array/access.rb +53 -0
- data/lib/active_support/core_ext/array/conversions.rb +183 -0
- data/lib/active_support/core_ext/array/extract_options.rb +20 -0
- data/lib/active_support/core_ext/array/grouping.rb +106 -0
- data/lib/active_support/core_ext/array/random_access.rb +12 -0
- data/lib/active_support/core_ext/array.rb +13 -0
- data/lib/active_support/core_ext/blank.rb +58 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +54 -0
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +140 -0
- data/lib/active_support/core_ext/class/removal.rb +50 -0
- data/lib/active_support/core_ext/class.rb +3 -0
- data/lib/active_support/core_ext/duplicable.rb +43 -0
- data/lib/active_support/core_ext/enumerable.rb +72 -0
- data/lib/active_support/core_ext/hash/conversions.rb +259 -0
- data/lib/active_support/core_ext/hash/keys.rb +52 -0
- data/lib/active_support/core_ext/hash.rb +8 -0
- data/lib/active_support/core_ext/module/aliasing.rb +74 -0
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +31 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +58 -0
- data/lib/active_support/core_ext/module.rb +16 -0
- data/lib/active_support/core_ext/object/conversions.rb +14 -0
- data/lib/active_support/core_ext/object/extending.rb +80 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +74 -0
- data/lib/active_support/core_ext/object/metaclass.rb +13 -0
- data/lib/active_support/core_ext/object/misc.rb +43 -0
- data/lib/active_support/core_ext/object.rb +5 -0
- data/lib/active_support/core_ext/string/inflections.rb +167 -0
- data/lib/active_support/core_ext/string.rb +7 -0
- data/lib/active_support/core_ext.rb +4 -0
- data/lib/active_support/inflections.rb +55 -0
- data/lib/active_support/inflector.rb +348 -0
- data/lib/active_support/vendor/builder-2.1.2/blankslate.rb +113 -0
- data/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +20 -0
- data/lib/active_support/vendor/builder-2.1.2/builder/css.rb +250 -0
- data/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +115 -0
- data/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +139 -0
- data/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +63 -0
- data/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +328 -0
- data/lib/active_support/vendor/builder-2.1.2/builder.rb +13 -0
- data/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb +1021 -0
- data/lib/active_support/vendor.rb +14 -0
- data/lib/active_support.rb +6 -0
- data/spec/case/association_test.rb +97 -0
- data/spec/case/base_test.rb +74 -0
- data/spec/case/callbacks_observers_test.rb +38 -0
- data/spec/case/callbacks_test.rb +424 -0
- data/spec/case/serialization_test.rb +87 -0
- data/spec/case/validations_test.rb +1482 -0
- data/spec/data.tch +0 -0
- data/spec/helper.rb +15 -0
- data/spec/light_cloud.yml +18 -0
- data/spec/model/account.rb +4 -0
- data/spec/model/topic.rb +26 -0
- data/spec/model/user.rb +8 -0
- metadata +173 -0
@@ -0,0 +1,200 @@
|
|
1
|
+
module ActiveObject
|
2
|
+
|
3
|
+
module Associations
|
4
|
+
def self.included(base)
|
5
|
+
base.send :include, HasOneAssociation
|
6
|
+
base.send :include, HasManyAssociation
|
7
|
+
end
|
8
|
+
|
9
|
+
module HasOneAssociation
|
10
|
+
def self.included(base)
|
11
|
+
base.extend ClassMethods
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
# has_one用于指明两个对象之间的关联。
|
17
|
+
#
|
18
|
+
# 一旦使用has_one,下列方法将被添加:
|
19
|
+
#
|
20
|
+
# [association]
|
21
|
+
# 返回关联对象. 如果没有找到则返回+nil+。
|
22
|
+
# [association=(associate)]
|
23
|
+
# 对关联对象赋值。
|
24
|
+
# [association.nil?]
|
25
|
+
# 如果没有关联对象,则返回+true+。
|
26
|
+
#
|
27
|
+
# (用第一个参数替换+association+,例如:
|
28
|
+
# <tt>has_one :manager</tt> 将添加 <tt>manager.nil?</tt>.)
|
29
|
+
#
|
30
|
+
# === 示例
|
31
|
+
#
|
32
|
+
# Account类定义了<tt>has_one :beneficiary</tt>,将添加:
|
33
|
+
# * <tt>Account#beneficiary</tt>
|
34
|
+
# * <tt>Account#beneficiary=(beneficiary)</tt>
|
35
|
+
# * <tt>Account#beneficiary.nil?</tt>
|
36
|
+
#
|
37
|
+
# === 选项
|
38
|
+
#
|
39
|
+
# 通过hash选项指定关联的行为
|
40
|
+
#
|
41
|
+
# 选项:
|
42
|
+
# [:class_name]
|
43
|
+
# 指定关联的类名。默认情况类名是有关联推断出来的,如果无法推断则需要显性指定。
|
44
|
+
#
|
45
|
+
# 选项示例:
|
46
|
+
# has_one :icon,:class_name=>"Photo"
|
47
|
+
#
|
48
|
+
def has_one(association, options = {})
|
49
|
+
|
50
|
+
class_name = options.delete(:class_name) || association.to_s.camelize
|
51
|
+
write_inheritable_attribute "#{association}_class",class_name # 保存关联的类名
|
52
|
+
attr_accessor "#{association}"
|
53
|
+
merge_attributes "#{association}_id" # 将关联id作为持久化属性
|
54
|
+
|
55
|
+
define_method("#{association}_id") do
|
56
|
+
self.instance_variable_get("@#{association}") ? self.instance_variable_get("@#{association}").id : nil
|
57
|
+
end
|
58
|
+
|
59
|
+
define_method("#{association}_id=") do |value|
|
60
|
+
self.instance_variable_set("@#{association}",self.class.read_inheritable_attribute("#{association}_class").constantize.find(value))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module HasManyAssociation
|
68
|
+
def self.included(base)
|
69
|
+
base.extend ClassMethods
|
70
|
+
end
|
71
|
+
|
72
|
+
class Collection
|
73
|
+
def initialize()
|
74
|
+
@objects = []
|
75
|
+
end
|
76
|
+
# 遍历关联对象集合
|
77
|
+
def each
|
78
|
+
@objects.each do |object|
|
79
|
+
yield object
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def each_with_index
|
84
|
+
@objects.each_with_index do |object,index|
|
85
|
+
yield object,index
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# 添加一个关联对象
|
90
|
+
def append(object)
|
91
|
+
@objects << object
|
92
|
+
end
|
93
|
+
|
94
|
+
# 插入一个关联对象
|
95
|
+
def insert(index,object)
|
96
|
+
@objects.insert(index,object)
|
97
|
+
end
|
98
|
+
|
99
|
+
# 删除一个关联对象
|
100
|
+
def delete(object)
|
101
|
+
@objects.delete(object)
|
102
|
+
end
|
103
|
+
|
104
|
+
def size
|
105
|
+
@objects.size
|
106
|
+
end
|
107
|
+
|
108
|
+
def clear
|
109
|
+
@objects.clear
|
110
|
+
end
|
111
|
+
|
112
|
+
def empty?
|
113
|
+
@objects.empty?
|
114
|
+
end
|
115
|
+
|
116
|
+
def object_ids
|
117
|
+
@objects.collect{|object| object.id}
|
118
|
+
end
|
119
|
+
|
120
|
+
def objects
|
121
|
+
@objects
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
module ClassMethods
|
126
|
+
|
127
|
+
# has_many用于指明两个对象之间的关联。
|
128
|
+
#
|
129
|
+
# 一旦使用has_many,下列方法将被添加:
|
130
|
+
# [associations.each]
|
131
|
+
# 遍历对象集合
|
132
|
+
# [associations]
|
133
|
+
# 返回关联的对象集合. 如果没有找到则返回空数组。
|
134
|
+
# [associations.append(object)]
|
135
|
+
# 添加一个关联对象。
|
136
|
+
# [associations.insert(object,index)]
|
137
|
+
# 插入一个关联对象。
|
138
|
+
# [associations.delete(object)]
|
139
|
+
# 删除一个关联对象。
|
140
|
+
# [associations.clear]
|
141
|
+
# 清除所有关联对象。
|
142
|
+
# [associations.size]
|
143
|
+
# 关联对象的数量。
|
144
|
+
# [association.empty?]
|
145
|
+
# 如果没有关联对象,则返回+true+。
|
146
|
+
#
|
147
|
+
# (用第一个参数替换+associations+,例如:
|
148
|
+
# <tt>has_many :managers</tt> 将添加 <tt>managers.empty?</tt>.)
|
149
|
+
#
|
150
|
+
# === 示例
|
151
|
+
#
|
152
|
+
# Account类定义了<tt>has_many :friends</tt>,将添加:
|
153
|
+
# * <tt>Account#friends</tt>
|
154
|
+
# * <tt>Account#friends.append(user)</tt>
|
155
|
+
# * <tt>Account#friends.delete(user)</tt>
|
156
|
+
# * <tt>Account#friends.clear</tt>
|
157
|
+
# * <tt>Account#friends.size</tt>
|
158
|
+
# * <tt>Account#friends.empty?</tt>
|
159
|
+
#
|
160
|
+
# === 选项
|
161
|
+
#
|
162
|
+
# 通过hash选项指定关联的行为
|
163
|
+
#
|
164
|
+
# 选项:
|
165
|
+
# [:class_name]
|
166
|
+
# 指定关联的类名。默认情况类名是有关联推断出来的,如果无法推断则需要显性指定。
|
167
|
+
#
|
168
|
+
# 选项示例:
|
169
|
+
# has_many :friends,:class_name=>"User"
|
170
|
+
#
|
171
|
+
def has_many(associations, options = {})
|
172
|
+
|
173
|
+
class_name = options.delete(:class_name) || associations.to_s.singularize.camelize
|
174
|
+
write_inheritable_attribute "#{associations}_class",class_name # 保存关联的类名
|
175
|
+
merge_attributes "#{associations}_ids" # 将关联ids作为持久化属性
|
176
|
+
|
177
|
+
define_method("#{associations}_ids") do
|
178
|
+
self.instance_variable_get("@#{associations}") ? self.instance_variable_get("@#{associations}").object_ids : []
|
179
|
+
end
|
180
|
+
|
181
|
+
define_method("#{associations}_ids=") do |value|
|
182
|
+
self.instance_variable_set("@#{associations}",Collection.new)
|
183
|
+
value.each do |object_id|
|
184
|
+
self.instance_variable_get("@#{associations}").append(self.class.read_inheritable_attribute("#{associations}_class").constantize.find(object_id))
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
define_method("#{associations}") do
|
189
|
+
self.instance_variable_set("@#{associations}",Collection.new) unless self.instance_variable_get("@#{associations}")
|
190
|
+
self.instance_variable_get("@#{associations}")
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
@@ -0,0 +1,415 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'uuid'
|
3
|
+
require 'json'
|
4
|
+
require 'active_object/adapters/light_cloud'
|
5
|
+
require 'active_object/adapters/tokyo_cabinet'
|
6
|
+
require 'active_object/adapters/tokyo_tyrant'
|
7
|
+
|
8
|
+
|
9
|
+
# 实现访问LightCloud的通用方法
|
10
|
+
module ActiveObject
|
11
|
+
class ActiveObjectError < StandardError;end
|
12
|
+
|
13
|
+
class ObjectNotFound < ActiveObjectError;end
|
14
|
+
|
15
|
+
class ObjectNotSaved < ActiveObjectError;end
|
16
|
+
|
17
|
+
class ConfigError < ActiveObjectError;end
|
18
|
+
|
19
|
+
# ActiveObject内建id属性,采用uuid格式,对象的key由对象类和uuid组成,中间用下划线相连。通过attribute指定需要持久化的属性。
|
20
|
+
#
|
21
|
+
# == 描述类
|
22
|
+
# ActiveObject所有类都是从Base类派生的,在派生新类时需要指定持久化存储的属性.就像下面一样:
|
23
|
+
#
|
24
|
+
# class User < ActiveObject::Base
|
25
|
+
# attribute :name,:email,:encrypt_password
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# 每个对象有默认的ID,如果想指定主关键字,可以通过primary_key指定
|
29
|
+
#
|
30
|
+
# class User < ActiveObject::Base
|
31
|
+
# primary_key :email
|
32
|
+
# attribute :name,:email,:encrypt_password
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# == 新建
|
36
|
+
# 可以通过hash参数新建对象,例如:
|
37
|
+
# user = User.new(:name => "David", :occupation => "Code Artist")
|
38
|
+
# user.name # => "David"
|
39
|
+
#
|
40
|
+
# 也可以使用块初始化对象:
|
41
|
+
#
|
42
|
+
# user = User.new do |u|
|
43
|
+
# u.name = "David"
|
44
|
+
# u.occupation = "Code Artist"
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# 当然,也可以在新建后对特定的属性赋值:
|
48
|
+
#
|
49
|
+
# user = User.new
|
50
|
+
# user.name = "David"
|
51
|
+
# user.occupation = "Code Artist"
|
52
|
+
#
|
53
|
+
# == 删除
|
54
|
+
# 删除主关键字与参数 +id+ 匹配的对象。
|
55
|
+
#
|
56
|
+
# ==== 参数
|
57
|
+
#
|
58
|
+
# * +id+ - 对象的主关键字.
|
59
|
+
#
|
60
|
+
# ==== 例子
|
61
|
+
#
|
62
|
+
# User.delete('aaron@nonobo.com')
|
63
|
+
|
64
|
+
|
65
|
+
class Base
|
66
|
+
write_inheritable_attribute :attributes,[:id]
|
67
|
+
write_inheritable_attribute :primary_key,nil
|
68
|
+
|
69
|
+
@@configurations = nil
|
70
|
+
@@database_model = nil
|
71
|
+
|
72
|
+
@@connection = nil
|
73
|
+
|
74
|
+
class << self
|
75
|
+
|
76
|
+
# 定义需要持久化的属性
|
77
|
+
# 示例:
|
78
|
+
# class User < ActiveObject::Base
|
79
|
+
# attribute :email,:name,:password # 表示email,name,password需要持久化存储
|
80
|
+
# end
|
81
|
+
def attribute(*options)
|
82
|
+
options.each do |attribute|
|
83
|
+
attr_accessor attribute
|
84
|
+
end
|
85
|
+
merge_attributes options
|
86
|
+
end
|
87
|
+
|
88
|
+
def attributes
|
89
|
+
read_inheritable_attribute(:attributes)
|
90
|
+
end
|
91
|
+
|
92
|
+
def primary_key(value=nil)
|
93
|
+
if value
|
94
|
+
write_inheritable_attribute :primary_key,value
|
95
|
+
else
|
96
|
+
read_inheritable_attribute(:primary_key)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# 配置ActiveObject访问的后台数据库支撑,目前支持LightCloud/TokyoTyrant/TokyoCabinet。
|
102
|
+
# 参数 +model+ 用于描述后台数据库的类型。
|
103
|
+
# :TC => 表示TokyoCabinet
|
104
|
+
# :TT => 表示TokyoTyrant
|
105
|
+
# :LC => 表示LightCloud
|
106
|
+
#
|
107
|
+
# 参数 +config+ 用于接收后台数据库的配置信息。
|
108
|
+
#
|
109
|
+
# 当model指定为TokyoCabinet数据库时,config为指定的文件名,例如:
|
110
|
+
# ActiveObject::Base.configure :TC, File.join(File.dirname(__FILE__),'act.tch')
|
111
|
+
# 这里需要注意的是指定的文件名后缀符合TokyoCabinet的约定规则。更多信息请参看:http://tokyocabinet.sourceforge.net/spex-en.html#tcadbapi
|
112
|
+
#
|
113
|
+
#
|
114
|
+
#
|
115
|
+
# 当model指定为TokyoTyrant数据库时, config为指定的远程服务器地址,例如:
|
116
|
+
# ActiveObject::Base.configure :TT, '127.0.0.1:54321'
|
117
|
+
#
|
118
|
+
# 当model指定为LightCloud数据库时, config可以接收符合配置规则的hash:
|
119
|
+
# ActiveObject::Base.configure :LC, {'user'=>{'lookup_one'=>['127.0.0.1:30001','127.0.0.1:33001'],'storage_one'=>['127.0.0.1:20001','127.0.0.1:24001']}}
|
120
|
+
# 也可以是配置文件的文件名。
|
121
|
+
# ActiveObject::Base.configure :LC, File.join(File.dirname(__FILE__),'config.yml')
|
122
|
+
#
|
123
|
+
def configure(model,config)
|
124
|
+
@@configurations = config
|
125
|
+
@@database_model = model
|
126
|
+
case @@database_model
|
127
|
+
when :TC
|
128
|
+
ActiveObject::Base.send :include,ActiveObjectTokyoCabinet
|
129
|
+
when :TT
|
130
|
+
ActiveObject::Base.send :include,ActiveObjectTokyoTyrant
|
131
|
+
when :LC
|
132
|
+
ActiveObject::Base.send :include,ActiveObjectLightCloud
|
133
|
+
else
|
134
|
+
raise ConfigError,'没有指定数据库类型!'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def configurations
|
139
|
+
@@configurations
|
140
|
+
end
|
141
|
+
|
142
|
+
# 返回当前所使用的数据库模型
|
143
|
+
# :TC表示采用的是TokyoCabinet
|
144
|
+
# :TT表示采用的是TokyoTyrant
|
145
|
+
# :LC表示采用的是LightCloud
|
146
|
+
def database_model
|
147
|
+
@@database_model
|
148
|
+
end
|
149
|
+
|
150
|
+
# 通过主关键字查找对象
|
151
|
+
#
|
152
|
+
# +id+ 参数表示需要找回的主关键字.
|
153
|
+
#
|
154
|
+
# ==== Example
|
155
|
+
# User.find('aaron@nonobo.com')
|
156
|
+
#
|
157
|
+
def find(id)
|
158
|
+
return nil if id.blank?
|
159
|
+
record = load(id)
|
160
|
+
record ? instance(id,record) : nil
|
161
|
+
end
|
162
|
+
|
163
|
+
# 查找该类的所有对象
|
164
|
+
# User.find_all => 取出所有的用户
|
165
|
+
#def find_all
|
166
|
+
#end
|
167
|
+
|
168
|
+
# 新建对象(或多个对象)并保存到数据库(假设都通过验证)
|
169
|
+
# 不管是否保存到数据库,都将返回对象.
|
170
|
+
#
|
171
|
+
# 参数 +attributes+ 可以是Hash或Hash数组.
|
172
|
+
#
|
173
|
+
# ==== 示例
|
174
|
+
# # 创建单个新对象
|
175
|
+
# User.create(:first_name => 'Jamie')
|
176
|
+
#
|
177
|
+
# # 创建多个对象
|
178
|
+
# User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])
|
179
|
+
#
|
180
|
+
# # 创建对象,并通过块进行其它属性的赋值.
|
181
|
+
# User.create(:first_name => 'Jamie') do |u|
|
182
|
+
# u.is_admin = false
|
183
|
+
# end
|
184
|
+
#
|
185
|
+
# # 创建多个对象,并通过块进行其它属性的赋值,每个对象都会执行块:
|
186
|
+
# User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
|
187
|
+
# u.is_admin = false
|
188
|
+
# end
|
189
|
+
def create(attributes = nil, &block)
|
190
|
+
if attributes.is_a?(Array)
|
191
|
+
attributes.collect { |attr| create(attr, &block) }
|
192
|
+
else
|
193
|
+
object = new(attributes)
|
194
|
+
yield(object) if block_given?
|
195
|
+
object.save
|
196
|
+
object
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
# 删除主关键字与参数 +id+ 匹配的对象,并且在删除之前执行所有的回调和过滤。
|
202
|
+
#
|
203
|
+
# ==== 参数
|
204
|
+
#
|
205
|
+
# * +id+ - 对象的主关键字.
|
206
|
+
#
|
207
|
+
# ==== 示例
|
208
|
+
# User.destroy('aaron@nonobo.com')
|
209
|
+
def destroy(id)
|
210
|
+
find(id).destroy
|
211
|
+
end
|
212
|
+
|
213
|
+
# 在适配器中重写
|
214
|
+
#def delete(id)
|
215
|
+
#end
|
216
|
+
|
217
|
+
def base_class
|
218
|
+
class_of_active_object_descendant(self)
|
219
|
+
end
|
220
|
+
|
221
|
+
def self_and_descendents_from_active_object#nodoc:
|
222
|
+
klass = self
|
223
|
+
classes = [klass]
|
224
|
+
while klass != klass.base_class
|
225
|
+
classes << klass = klass.superclass
|
226
|
+
end
|
227
|
+
classes
|
228
|
+
rescue
|
229
|
+
[self]
|
230
|
+
end
|
231
|
+
|
232
|
+
# 通过id转换成存取用的key
|
233
|
+
def id_to_key(id)
|
234
|
+
"#{self.to_s}_#{id}"
|
235
|
+
end
|
236
|
+
|
237
|
+
# 将key转换成id
|
238
|
+
def key_to_id(key)
|
239
|
+
key[key.index("_")+1..-1]
|
240
|
+
end
|
241
|
+
|
242
|
+
def deserialize_attributes(raw_record)
|
243
|
+
Marshal.load(raw_record)
|
244
|
+
end
|
245
|
+
|
246
|
+
def serialize_attributes(record)
|
247
|
+
Marshal.dump(record)
|
248
|
+
end
|
249
|
+
|
250
|
+
protected
|
251
|
+
def class_of_active_object_descendant(klass)
|
252
|
+
if klass.superclass == Base
|
253
|
+
klass
|
254
|
+
elsif klass.superclass.nil?
|
255
|
+
raise ActiveObjectError, "#{name} doesn't belong in a hierarchy descending from ActiveObject"
|
256
|
+
else
|
257
|
+
class_of_active_object_descendant(klass.superclass)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def configurations=(value)
|
262
|
+
@@configurations= value
|
263
|
+
end
|
264
|
+
|
265
|
+
def database_model=(value)
|
266
|
+
@@database_model = value
|
267
|
+
end
|
268
|
+
|
269
|
+
# 合并属性
|
270
|
+
def merge_attributes(options)
|
271
|
+
attrs = read_inheritable_attribute :attributes
|
272
|
+
attrs << options
|
273
|
+
write_inheritable_attribute :attributes, attrs.flatten.uniq
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
# 在设配器中重写
|
278
|
+
#def load(id)
|
279
|
+
#end
|
280
|
+
|
281
|
+
# 构建一个对象实例
|
282
|
+
def instance(id,record)
|
283
|
+
object = new(record)
|
284
|
+
object.send "id=",id
|
285
|
+
object.instance_variable_set(:@new_record,false)
|
286
|
+
object
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
def initialize(attributes = nil)
|
292
|
+
self.id = UUID.new.generate
|
293
|
+
@new_record = true
|
294
|
+
assign_attributes(attributes)
|
295
|
+
object = yield self if block_given?
|
296
|
+
object
|
297
|
+
end
|
298
|
+
|
299
|
+
def attributes
|
300
|
+
self.class.attributes
|
301
|
+
end
|
302
|
+
|
303
|
+
# id用来标识对象
|
304
|
+
# 为了能够通过前缀访问对象,在uuid之前加入对象的类名作为存取的key
|
305
|
+
def id=(value)
|
306
|
+
@key = self.class.id_to_key(value)
|
307
|
+
end
|
308
|
+
|
309
|
+
def id
|
310
|
+
self.class.key_to_id(@key)
|
311
|
+
end
|
312
|
+
|
313
|
+
# 如果对象没有被存储,表明对象还是新记录,返回true,否则返回false.
|
314
|
+
def new_record?
|
315
|
+
@new_record
|
316
|
+
end
|
317
|
+
|
318
|
+
# 如果对象已经被删除,返回true,否则返回false。
|
319
|
+
def destroyed?
|
320
|
+
@destroyed || false
|
321
|
+
end
|
322
|
+
|
323
|
+
# 从数据库中删除对象
|
324
|
+
# 不像 #destroy, 这个方法不运行 +before_delete+ 和 +after_delete+ 回调.
|
325
|
+
def delete
|
326
|
+
self.class.delete(id) unless new_record?
|
327
|
+
@destroyed = true
|
328
|
+
end
|
329
|
+
|
330
|
+
def destroy
|
331
|
+
delete
|
332
|
+
end
|
333
|
+
|
334
|
+
# 从数据库中重新加载对象的属性
|
335
|
+
def reload
|
336
|
+
#raise "Object is deleted" if destroyed?
|
337
|
+
unless new_record?
|
338
|
+
begin
|
339
|
+
attributes = self.class.send :load, self.id
|
340
|
+
assign_attributes(attributes)
|
341
|
+
true
|
342
|
+
rescue
|
343
|
+
false
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# :call-seq:
|
349
|
+
# save(perform_validation = true)
|
350
|
+
#
|
351
|
+
# 保存对象.
|
352
|
+
#
|
353
|
+
# 如果对象是新对象,那么在数据库中创建。否则,如果对象是数据库中已经存在的对象,那么更新数据库
|
354
|
+
#
|
355
|
+
# 如果 +perform_validation+ 是true,将执行验证。如果验证失败,那么动作被取消,并且返回false。
|
356
|
+
#
|
357
|
+
# +save+ 相关联的一系列回调. 如果任何一个<tt>before_*</tt>回调返回 +false+,那么+save+动作被取消并返回 +false+.
|
358
|
+
def save
|
359
|
+
create_or_update
|
360
|
+
end
|
361
|
+
|
362
|
+
# 保存对象.
|
363
|
+
#
|
364
|
+
# 如果对象是新对象,那么在数据库中创建。否则,如果对象是数据库中已经存在的对象,那么更新数据库
|
365
|
+
#
|
366
|
+
# 执行<tt>save!</tt>时,验证总是被运行。只要有任意一个执行失败都将抛出 ActiveObject::ObjectInvalid异常。
|
367
|
+
#
|
368
|
+
# +save+ 相关联的一系列回调. 如果任何一个<tt>before_*</tt>回调返回 +false+,那么+save+动作被取消并返回 +false+,并且抛出ActiveObject::RecordNotSaved.
|
369
|
+
def save!
|
370
|
+
create_or_update || raise(ObjectNotSaved)
|
371
|
+
end
|
372
|
+
|
373
|
+
|
374
|
+
private
|
375
|
+
def attribute_present?(attribute)
|
376
|
+
value = read_attribute(attribute)
|
377
|
+
!value.blank?
|
378
|
+
end
|
379
|
+
|
380
|
+
def assign_attributes(attributes=nil)
|
381
|
+
attributes.each do |key,value|
|
382
|
+
self.send "#{key}=",value
|
383
|
+
end unless attributes.nil?
|
384
|
+
end
|
385
|
+
|
386
|
+
def create_or_update
|
387
|
+
result = new_record? ? create : update
|
388
|
+
@destroyed = false
|
389
|
+
@new_record = false
|
390
|
+
result != false
|
391
|
+
end
|
392
|
+
|
393
|
+
def serialize_attributes
|
394
|
+
record = {}
|
395
|
+
self.class.attributes.each do |attribute|
|
396
|
+
record.merge!({attribute=>(self.send attribute)})
|
397
|
+
end
|
398
|
+
self.class.serialize_attributes(record)
|
399
|
+
end
|
400
|
+
|
401
|
+
def create
|
402
|
+
self.id = self.send self.class.primary_key if self.class.primary_key
|
403
|
+
set
|
404
|
+
end
|
405
|
+
|
406
|
+
def update
|
407
|
+
set
|
408
|
+
end
|
409
|
+
|
410
|
+
# 保存记录,在适配器中重写
|
411
|
+
#def set
|
412
|
+
#end
|
413
|
+
end
|
414
|
+
|
415
|
+
end
|