zeng 0.0.1
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/CHANGE +3 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +89 -0
- data/Rakefile +37 -0
- data/TODOLIST +5 -0
- data/init.rb +4 -0
- data/lib/cute_kv/adapters/light_cloud.rb +22 -0
- data/lib/cute_kv/adapters/tokyo_cabinet.rb +33 -0
- data/lib/cute_kv/adapters/tokyo_tyrant.rb +22 -0
- data/lib/cute_kv/associations.rb +285 -0
- data/lib/cute_kv/connector.rb +27 -0
- data/lib/cute_kv/document.rb +328 -0
- data/lib/cute_kv/ext/string.rb +34 -0
- data/lib/cute_kv/ext/symbol.rb +9 -0
- data/lib/cute_kv/indexer.rb +102 -0
- data/lib/cute_kv/serialization.rb +95 -0
- data/lib/cute_kv/serializers/json_serializer.rb +75 -0
- data/lib/cute_kv/serializers/xml_serializer.rb +325 -0
- data/lib/cute_kv/timestamp.rb +56 -0
- data/lib/cute_kv/validations.rb +68 -0
- data/lib/cutekv.rb +17 -0
- data/spec/asso.yml +23 -0
- data/spec/asso_sin_plural.yml +36 -0
- data/spec/case/associations_test.rb +313 -0
- data/spec/case/document_docking_test.rb +103 -0
- data/spec/case/document_test.rb +184 -0
- data/spec/case/indexer_test.rb +40 -0
- data/spec/case/serialization_test.rb +78 -0
- data/spec/case/sin_plu_dic_test.rb +29 -0
- data/spec/case/symmetry_test.rb +80 -0
- data/spec/case/timestamp_test.rb +65 -0
- data/spec/case/validations_test.rb +74 -0
- data/spec/helper.rb +29 -0
- data/spec/light_cloud.yml +9 -0
- data/spec/model/Account.rb +5 -0
- data/spec/model/Book.rb +6 -0
- data/spec/model/Friend.rb +4 -0
- data/spec/model/Icon.rb +5 -0
- data/spec/model/Project.rb +5 -0
- data/spec/model/Topic.rb +26 -0
- data/spec/model/User.rb +6 -0
- data/tags +322 -0
- metadata +124 -0
data/CHANGE
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Aaron
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
= CuteKV -- based at Ruby for object-key/value map
|
2
|
+
|
3
|
+
|
4
|
+
== Main features
|
5
|
+
* Independent Object Storage
|
6
|
+
|
7
|
+
Through backend_configure to appoint storage location
|
8
|
+
class User < ActiveObject::Base
|
9
|
+
backend_configure :TT,"127.0.0.1:1987"
|
10
|
+
end
|
11
|
+
|
12
|
+
* Customize define persistent properties
|
13
|
+
you can assign persitent properties by <t>assign</t> method,and set default value for
|
14
|
+
each property.
|
15
|
+
|
16
|
+
class User
|
17
|
+
include CuteKV::Document
|
18
|
+
backend_configure :TT,"127.0.0.1:1987"
|
19
|
+
assign :name,:email, :gender=>'male', :age=>25
|
20
|
+
end
|
21
|
+
|
22
|
+
==Object's associations
|
23
|
+
|
24
|
+
Using CuteKV::associations module, we can description associations between objects
|
25
|
+
|
26
|
+
|
27
|
+
class User
|
28
|
+
include CuteKV::Document
|
29
|
+
backend_configure :TT,"127.0.0.1:1987"
|
30
|
+
assign :name,:email, :gender=>'male', :age=>25
|
31
|
+
end
|
32
|
+
|
33
|
+
CuteKV::associations::map(User=>:icon, Icon=>:user) #=>user has one icon and icon belongs to one user
|
34
|
+
CuteKV::associations::map(User=>:friends) #=>user has many friends
|
35
|
+
|
36
|
+
class Icon < ActiveObject::Base
|
37
|
+
include CuteKV::Document
|
38
|
+
backend_configure :TT,"127.0.0.1:1987"
|
39
|
+
assign :content
|
40
|
+
end
|
41
|
+
|
42
|
+
==Validations
|
43
|
+
now CuteKV support validations by a simple method <t>validate</t> from CuteKV::Validations module
|
44
|
+
I just keep it simple or i will improve it to approach activerecord's validations
|
45
|
+
class User
|
46
|
+
include CuteKV::Document
|
47
|
+
incude CuteKV::Validations
|
48
|
+
backend_configure :TT,"127.0.0.1:1987"
|
49
|
+
assign :name,:email, :gender=>'male', :age=>25
|
50
|
+
validate :name_presence_valid
|
51
|
+
|
52
|
+
def name_presence_valid
|
53
|
+
errors.add(:name, "name should not blank") if self.name.blank?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
@jim = User.create()
|
58
|
+
@jim.save #=>nil
|
59
|
+
User.find(@jim.id) #=>nil
|
60
|
+
@jim.errors_message_on(:name) #=>"name should not blank"
|
61
|
+
|
62
|
+
|
63
|
+
==Index
|
64
|
+
class User
|
65
|
+
include CuteKV::Document
|
66
|
+
backend_configure :TT,"127.0.0.1:1987"
|
67
|
+
assign :name,:email, :gender=>'male', :age=>25
|
68
|
+
end
|
69
|
+
@jim = User.create(:name=>"jim", :email=>"jim@nonobo.com")
|
70
|
+
@aaron = User.create(:name=>"aaron", :email=>"aaron@nonobo.com")
|
71
|
+
@jack= User.create(:name=>"jack", :email=>"jack@nonbo.com")
|
72
|
+
@lucy = User.create(:name=>"lucy", :email=>"lucy@nonobo.com")
|
73
|
+
Useing CuteKV::Indexer module, you can build index for object, just like:
|
74
|
+
CuteKV::Indexer::map(User=>[:name, :email, :age])
|
75
|
+
then,
|
76
|
+
User.indexes << @jim
|
77
|
+
User.indexes << @aaron
|
78
|
+
User.indexes << @lucy
|
79
|
+
User.find_all_by_name("jim") #=>@jim
|
80
|
+
User.find_all_by_age(25) #=>@jim, @aaron, @lucy, @jack
|
81
|
+
|
82
|
+
== Supoort multiple database
|
83
|
+
CuteKV using adapter to connect database.now backend support:TokyoCabinet/TokyoTyrant/LightCloud。
|
84
|
+
|
85
|
+
|
86
|
+
== Using in rails
|
87
|
+
in environment.rb, you will add
|
88
|
+
require 'cutekv'
|
89
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
task :default=>:test
|
6
|
+
|
7
|
+
task :test do
|
8
|
+
Dir['spec/case/**/*'].each {|test|
|
9
|
+
sh "ruby #{test}" if test =~ /(_test\.rb)$/
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "start test for given file"
|
14
|
+
task :test_file, [:file] do |t, args|
|
15
|
+
sh "ruby spec/case/#{args.file}_test.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "创建gemspec文件"
|
19
|
+
task :gemspec do
|
20
|
+
spec = Gem::Specification.new do |s|
|
21
|
+
s.name = %{zeng}
|
22
|
+
s.version = '0.0.1'
|
23
|
+
s.summary = 'A chinese fishing tool'
|
24
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
25
|
+
|
26
|
+
s.email = ["kayak.jiang@gmail.com"]
|
27
|
+
s.authors = "Guimin Jiang"
|
28
|
+
s.files = Dir["./**/*"].delete_if {|path| path =~ /.gem$/}
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
s.required_ruby_version = Gem::Requirement.new(">= 1.8.6")
|
31
|
+
s.rubygems_version = %q{1.3.4}
|
32
|
+
s.add_dependency(%q<ffi>)
|
33
|
+
end
|
34
|
+
|
35
|
+
File.open("zeng.gemspec", "w") {|f| f << spec.to_ruby }
|
36
|
+
end
|
37
|
+
|
data/init.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# 访问LightCloud的加载模块
|
2
|
+
require 'lightcloud'
|
3
|
+
module CuteKV
|
4
|
+
module Adapters
|
5
|
+
module TokyoCloud
|
6
|
+
def put(key, value)
|
7
|
+
@db.set(key, value)
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(key)
|
11
|
+
@db.get(key)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def establish(conf)
|
16
|
+
conf = YAML.load_file(conf) if conf.is_a?(String)
|
17
|
+
lookup_nodes, storage_nodes = LightCloud.generate_nodes(conf)
|
18
|
+
@db = LightCloud.new(lookup_nodes, storage_nodes)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# 访问TokyoCabinet的加载模块
|
3
|
+
require 'rufus/tokyo'
|
4
|
+
module CuteKV
|
5
|
+
module Adapters
|
6
|
+
module TokyoCabinet
|
7
|
+
def put(key, value)
|
8
|
+
@db[key] = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(key)
|
12
|
+
@db[key]
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete(key)
|
16
|
+
@db.delete(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def infos
|
20
|
+
{:adapter=>@adapter, :host=>@host, :port=>@port}
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(method, *args)
|
24
|
+
@db.send method, *args
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def establish(conf)
|
29
|
+
@db = Rufus::Tokyo::Cabinet.new(conf)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# 访问TokyoTyrant的加载模块
|
2
|
+
require 'rufus/tokyo'
|
3
|
+
require 'cute_kv/adapters/tokyo_cabinet'
|
4
|
+
module CuteKV
|
5
|
+
module Adapters
|
6
|
+
module TokyoTyrant
|
7
|
+
include CuteKV::Adapters::TokyoCabinet
|
8
|
+
private
|
9
|
+
def establish(conf)
|
10
|
+
if conf.is_a? Hash
|
11
|
+
@host = conf[:host] || conf["host"]
|
12
|
+
@port = (conf[:port] || conf["port"]).to_i
|
13
|
+
else
|
14
|
+
conf = conf.split(':')
|
15
|
+
@host = conf[0]
|
16
|
+
@port = conf[1].to_i
|
17
|
+
end
|
18
|
+
@db = Rufus::Tokyo::Tyrant.new(@host, @port)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
module CuteKV
|
2
|
+
module Associations
|
3
|
+
|
4
|
+
Map = Class.new
|
5
|
+
Collection = Class.new(Array) {
|
6
|
+
def to_json(options={})
|
7
|
+
"[#{self.map{|c| c.to_json(options)}.join(',')}]"
|
8
|
+
end
|
9
|
+
}
|
10
|
+
|
11
|
+
class Symmetry
|
12
|
+
|
13
|
+
def initialize(asso={})
|
14
|
+
@asso_string = parse(asso)
|
15
|
+
@assos = @asso_string.split("#")
|
16
|
+
end
|
17
|
+
|
18
|
+
def mirror(object)
|
19
|
+
m_o = @assos[@assos.size - 1 - @assos.index(object.to_s)]
|
20
|
+
m_o = m_o.constantize if object.is_a? Class
|
21
|
+
m_o = m_o.to_sym if object.is_a? Symbol
|
22
|
+
m_o
|
23
|
+
end
|
24
|
+
|
25
|
+
def each
|
26
|
+
asso = [[@assos[0].constantize, @assos[1].to_sym ],[@assos[-1].constantize, @assos[-2].to_sym]].uniq
|
27
|
+
asso.each {|a| yield a[0], a[-1]}
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def parse(asso={})
|
32
|
+
keys = asso.keys
|
33
|
+
values = asso.values.flatten
|
34
|
+
"#{keys[0]}##{values[0]}##{values[-1]}##{keys[-1]}"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.included(base)
|
40
|
+
base.send :include, InstanceMethods
|
41
|
+
base.extend ClassMethods
|
42
|
+
end
|
43
|
+
|
44
|
+
module InstanceMethods
|
45
|
+
|
46
|
+
def initialize(key, ids)
|
47
|
+
@key_infos = key.split('#')
|
48
|
+
@klass = @key_infos[-1].constantize
|
49
|
+
@key = key
|
50
|
+
@ids = deserialize ids
|
51
|
+
end
|
52
|
+
|
53
|
+
def ids
|
54
|
+
@ids
|
55
|
+
end
|
56
|
+
|
57
|
+
def relex(object)
|
58
|
+
r_k = @key_infos[0]
|
59
|
+
r_v = @key_infos[1]
|
60
|
+
k = @key_infos[-1]
|
61
|
+
v = @key_infos[-2]
|
62
|
+
key = "#{k}##{v}##{object.id}#relations##{r_v}##{r_k}"
|
63
|
+
map = self.class.find(key) || self.class.create(key, [])
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def objects
|
68
|
+
map = self
|
69
|
+
#it is very strange! when i use 'id', i can't use the method 'remove' correctly, so i use '_id'
|
70
|
+
_id = @key_infos[2]
|
71
|
+
_klass = @klass
|
72
|
+
_rv = @key_infos[1]
|
73
|
+
objs = Collection.new
|
74
|
+
objs.replace self.ids.collect {|id| @klass.find(id)}.compact
|
75
|
+
self.ids = objs.map(&:id) unless objs.size == self.ids.size
|
76
|
+
Collection.class_eval {
|
77
|
+
define_method(:<<){|object|
|
78
|
+
return unless object.is_a? _klass
|
79
|
+
if _rv.singular?
|
80
|
+
map.send(:ids=, [object.id])
|
81
|
+
else
|
82
|
+
map.ids << object.id
|
83
|
+
end
|
84
|
+
rel_map = map.relex(object)
|
85
|
+
rel_map.ids << _id
|
86
|
+
map.save
|
87
|
+
rel_map.save
|
88
|
+
}
|
89
|
+
|
90
|
+
define_method(:remove) {|object|
|
91
|
+
return unless object.is_a? _klass
|
92
|
+
map.ids.delete(object.id)
|
93
|
+
rel_map = map.relex(object)
|
94
|
+
rel_map.ids.delete(_id)
|
95
|
+
map.save
|
96
|
+
rel_map.save
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
}
|
101
|
+
objs
|
102
|
+
end
|
103
|
+
|
104
|
+
def save
|
105
|
+
self.class.backend[@key] = serialize @ids
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
private
|
110
|
+
def ids=(ids)
|
111
|
+
return unless ids.is_a? Array
|
112
|
+
@ids = ids
|
113
|
+
end
|
114
|
+
|
115
|
+
def serialize(ids)
|
116
|
+
self.class.send :serialize, ids
|
117
|
+
end
|
118
|
+
|
119
|
+
def deserialize(raw_ids)
|
120
|
+
self.class.send :deserialize, raw_ids
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
module ClassMethods
|
127
|
+
|
128
|
+
def connect(class_obj)
|
129
|
+
@backend = class_obj.backend
|
130
|
+
@class_obj = class_obj
|
131
|
+
end
|
132
|
+
|
133
|
+
def find(key)
|
134
|
+
new(key, @backend[key]) if @backend[key]
|
135
|
+
end
|
136
|
+
|
137
|
+
def create(key,ids=[])
|
138
|
+
ids = serialize ids
|
139
|
+
@backend[key] = ids
|
140
|
+
new(key, ids)
|
141
|
+
end
|
142
|
+
|
143
|
+
def backend
|
144
|
+
@backend
|
145
|
+
end
|
146
|
+
|
147
|
+
def find_or_create(key)
|
148
|
+
find(key) || create(key, [])
|
149
|
+
end
|
150
|
+
|
151
|
+
def gen_key(k, v, object, r_v, r_k)
|
152
|
+
key = "#{k}##{v}##{object.id}#relations##{r_v}##{r_k}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def draw(k, v, object, r_v, r_k)
|
156
|
+
key = gen_key(k, v, object, r_v, r_k)
|
157
|
+
find_or_create(key)
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def serialize(ids)
|
163
|
+
@class_obj.serialize(ids)
|
164
|
+
end
|
165
|
+
|
166
|
+
def deserialize(raw_ids)
|
167
|
+
@class_obj.deserialize(raw_ids)
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
class << self
|
173
|
+
# Although relations between real word's objects are complex, we abstract all relations to three
|
174
|
+
# type relations: # <tt>one_to_one</tt>, # <tt>one_to_many</tt>, # <tt>many_to_many</tt>
|
175
|
+
#
|
176
|
+
# == One_To_One
|
177
|
+
# class User < ActiveObject::Base
|
178
|
+
# assign :name, :gender=>"male"
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# class Icon < ActiveObject::Base
|
182
|
+
# assign :path
|
183
|
+
# end
|
184
|
+
# @aaron = User.create(:name=>"aaron")
|
185
|
+
# @icon = Icon.create(:path=>"/tmp/aaron.jpg")
|
186
|
+
#
|
187
|
+
# Associations::map(User=>:icon, Icon=>:user)
|
188
|
+
# User will add a instance method :icon
|
189
|
+
# Icon will add a instance method :user
|
190
|
+
# @aaron.icon = @icon
|
191
|
+
# aaron = User.find(@aaron.id)
|
192
|
+
# aaron.icon.path #=>"/tmp/aaron.jpg"
|
193
|
+
# icon = Icon.find(@icon.id)
|
194
|
+
# icon.user.name #=>"aaron"
|
195
|
+
#
|
196
|
+
# Associations::map(User=>[:wife, :husband])
|
197
|
+
# @rita = User.create(:name=>"rita", :gender=>'female')
|
198
|
+
# @aaron.wife = @rita
|
199
|
+
# @aaron.wife #=>@rita
|
200
|
+
# @rita.husband #=>@aaron
|
201
|
+
#
|
202
|
+
# == One_To_Many
|
203
|
+
# Associations::map(User=>:books, Book=>:owner)
|
204
|
+
# @book_ruby = Book.create(:name=>"Ruby")
|
205
|
+
# @book_java = Book.create(:name=>"Java")
|
206
|
+
#
|
207
|
+
# == Many_To_Many
|
208
|
+
# Associations::map(User=>:projects, Project=>:members)
|
209
|
+
# @aaron = User.create(:name=>"aaron")
|
210
|
+
# @nonobo = Project.create(:name=>"nonobo")
|
211
|
+
# @admin = Project.create(:name=>"admin")
|
212
|
+
# @aaron.prjects << @nonobo
|
213
|
+
# @aaron.prjects << @admin
|
214
|
+
# @aaron.projects #=>[@nonobo, @admin]
|
215
|
+
# @nonobo.members #=>[@aaron]
|
216
|
+
# @aaron.projects.remove(@nonbo)
|
217
|
+
# @nonbo.members #=> []
|
218
|
+
# @aaron.projects #=> [@admin]
|
219
|
+
#
|
220
|
+
#
|
221
|
+
def map(asso)
|
222
|
+
if asso.is_a? String
|
223
|
+
#load classes's associations from yml file
|
224
|
+
assos = YAML::load(IO.read(asso))
|
225
|
+
assos.each {|asso| map(constantize_asso_keys(asso)) }
|
226
|
+
else
|
227
|
+
singus = Array(asso.delete(:singular)).compact
|
228
|
+
Dic::SIN_WORDS.add(singus) unless singus.empty?
|
229
|
+
pluras = Array(asso.delete(:plural)).compact
|
230
|
+
Dic::PLU_WORDS.add(pluras) unless pluras.empty?
|
231
|
+
symmetry = Symmetry.new(asso)
|
232
|
+
symmetry.each {|k,v|
|
233
|
+
r_k = symmetry.mirror(k)
|
234
|
+
r_v = symmetry.mirror(v)
|
235
|
+
asso_map = Map.send(:include, self)
|
236
|
+
asso_map.connect(k)
|
237
|
+
k.class_eval {
|
238
|
+
define_method(v) {
|
239
|
+
map = asso_map.draw(k,v,self,r_v,r_k)
|
240
|
+
if v.singular?
|
241
|
+
obj = map.objects.last
|
242
|
+
return if obj.nil?
|
243
|
+
def obj.remove(object)
|
244
|
+
Collection.new.replace([self]).remove(object)
|
245
|
+
end
|
246
|
+
obj
|
247
|
+
else
|
248
|
+
map.objects
|
249
|
+
end
|
250
|
+
}
|
251
|
+
|
252
|
+
define_method("#{v}=") {|object|
|
253
|
+
return if object.nil?
|
254
|
+
map = asso_map.draw(k,v,self,r_v,r_k)
|
255
|
+
vo = self.send(v)
|
256
|
+
vo.send(r_v).remove(self) if vo
|
257
|
+
rvo = object.send(r_v)
|
258
|
+
rvo.send(v).remove(object) if r_v.singular? && rvo
|
259
|
+
map.objects << object
|
260
|
+
} if v.singular?
|
261
|
+
|
262
|
+
}
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
protected
|
269
|
+
|
270
|
+
def constantize_asso_keys(asso)
|
271
|
+
h = {}
|
272
|
+
plurs = asso.delete("plural").split(" ") if asso["plural"]
|
273
|
+
sins = asso.delete("singular").split(" ") if asso["singular"]
|
274
|
+
h[:plural] = plurs if plurs
|
275
|
+
h[:singular] = sins if sins
|
276
|
+
asso.each {|k,v| h[k.constantize] = v.split(' ') }
|
277
|
+
h
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module CuteKV
|
2
|
+
class Connector
|
3
|
+
def self.config(adapter)
|
4
|
+
case adapter.to_sym
|
5
|
+
when :TC
|
6
|
+
require 'cute_kv/adapters/tokyo_cabinet'
|
7
|
+
include CuteKV::Adapters::TokyoCabinet
|
8
|
+
when :TT
|
9
|
+
require 'cute_kv/adapters/tokyo_tyrant'
|
10
|
+
include CuteKV::Adapters::TokyoTyrant
|
11
|
+
when :LC
|
12
|
+
require 'cute_kv/adapters/light_cloud'
|
13
|
+
include CuteKV::Adapters::TokyoCloud
|
14
|
+
else
|
15
|
+
raise ConfigError,'没有指定数据库类型!'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(adapter, conf)
|
20
|
+
@adapter = adapter
|
21
|
+
self.class.config(adapter)
|
22
|
+
establish(conf)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|