zeng 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|