zeng 0.0.1 → 0.0.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/README.md +67 -0
- data/Rakefile +21 -19
- data/book.rb +23 -0
- data/{init.rb → lib/zeng.rb} +5 -1
- data/lib/{cute_kv → zeng}/adapters/tokyo_cabinet.rb +7 -6
- data/lib/zeng/adapters/tokyo_tyrant.rb +30 -0
- data/lib/zeng/connector.rb +28 -0
- data/lib/{cute_kv → zeng}/document.rb +7 -12
- data/lib/{cute_kv → zeng}/indexer.rb +2 -2
- data/spec/case/document_test.rb +174 -174
- data/spec/case/indexer_test.rb +31 -31
- data/spec/helper.rb +12 -14
- data/spec/model/Account.rb +3 -3
- data/spec/model/Book.rb +2 -2
- data/spec/model/Friend.rb +3 -3
- data/spec/model/Icon.rb +3 -3
- data/spec/model/Project.rb +2 -2
- data/spec/model/User.rb +3 -4
- metadata +26 -49
- data/README.rdoc +0 -89
- data/lib/cute_kv/adapters/light_cloud.rb +0 -22
- data/lib/cute_kv/adapters/tokyo_tyrant.rb +0 -22
- data/lib/cute_kv/associations.rb +0 -285
- data/lib/cute_kv/connector.rb +0 -27
- data/lib/cute_kv/ext/string.rb +0 -34
- data/lib/cute_kv/ext/symbol.rb +0 -9
- data/lib/cute_kv/serialization.rb +0 -95
- data/lib/cute_kv/serializers/json_serializer.rb +0 -75
- data/lib/cute_kv/serializers/xml_serializer.rb +0 -325
- data/lib/cute_kv/timestamp.rb +0 -56
- data/lib/cute_kv/validations.rb +0 -68
- data/lib/cutekv.rb +0 -17
- data/spec/asso.yml +0 -23
- data/spec/asso_sin_plural.yml +0 -36
- data/spec/case/associations_test.rb +0 -313
- data/spec/case/document_docking_test.rb +0 -103
- data/spec/case/serialization_test.rb +0 -78
- data/spec/case/sin_plu_dic_test.rb +0 -29
- data/spec/case/symmetry_test.rb +0 -80
- data/spec/case/timestamp_test.rb +0 -65
- data/spec/case/validations_test.rb +0 -74
- data/spec/light_cloud.yml +0 -9
- data/spec/model/Topic.rb +0 -26
- data/tags +0 -322
data/spec/case/indexer_test.rb
CHANGED
@@ -3,38 +3,38 @@ ModelDivider.divide "User", "Icon", "Project"
|
|
3
3
|
|
4
4
|
class IndexerTest < Test::Unit::TestCase
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
def setup
|
7
|
+
User.clear
|
8
|
+
Project.clear
|
9
|
+
@aaron = User.create(:name=>'aaron', :email=>'aaron@nonobo.com')
|
10
|
+
@jim = User.create(:name=>'jim', :email=>'jim@nonobo.com')
|
11
|
+
@jim_d = User.create(:name=>'jim', :email=>'aaron@nonobo.com')
|
12
|
+
@jack = User.create(:name=>'jack', :email=>'jack@nonobo.com')
|
13
|
+
@kame = User.create(:name=>'kame', :email=>'kame@nonobo.com')
|
14
|
+
@nonobo = Project.create(:name=>"nonobo")
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
17
|
+
def test_indexer_base
|
18
|
+
assert Zeng::Indexer::map(User=>['name', 'email'])
|
19
|
+
assert Zeng::Indexer::map(Project=>'created_at')
|
20
|
+
assert User.indexes == []
|
21
|
+
User.indexes << @aaron
|
22
|
+
User.indexes << @jim
|
23
|
+
User.indexes << @jim_d
|
24
|
+
User.indexes << @jack
|
25
|
+
User.indexes << @jim
|
26
|
+
User.indexes << @aaron
|
27
|
+
assert User.indexes.size == 4
|
28
|
+
assert User.indexes.include?([@aaron.id,{"id"=>@aaron.id, "name"=>@aaron.name, "email"=>@aaron.email}])
|
29
|
+
assert User.indexes.include?([@jim.id,{"id"=>@jim.id, "name"=>@jim.name, "email"=>@jim.email}])
|
30
|
+
assert User.indexes.include?([@jim_d.id,{"id"=>@jim_d.id, "name"=>@jim_d.name, "email"=>@jim_d.email}])
|
31
|
+
assert User.indexes.include?([@jack.id,{"id"=>@jack.id, "name"=>@jack.name, "email"=>@jack.email}])
|
32
|
+
assert User.respond_to?(:find_all_by_email)
|
33
|
+
assert User.find_all_by_name("aaron")[0].name=="aaron"
|
34
|
+
assert User.find_all_by_name("jim").size==2
|
35
|
+
assert_equal User.find_all_by_email("aaron@nonobo.com").size,2
|
36
|
+
assert_equal User.find_all_by_email("aaron@nonobo.com")[0].email, "aaron@nonobo.com"
|
37
|
+
end
|
38
38
|
|
39
39
|
|
40
40
|
end
|
data/spec/helper.rb
CHANGED
@@ -1,27 +1,25 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
|
3
|
-
require File.join(File.dirname(__FILE__), '..','lib','cutekv')
|
4
|
-
|
2
|
+
require File.join(File.dirname(__FILE__), '..','lib','zeng')
|
5
3
|
require 'test/unit'
|
6
4
|
|
7
5
|
def uses_mocha(description)
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
require 'rubygems'
|
7
|
+
require 'mocha'
|
8
|
+
yield
|
11
9
|
rescue LoadError
|
12
|
-
|
10
|
+
$stderr.puts "Skipping #{description} tests. `gem install mocha` and try again."
|
13
11
|
end
|
14
12
|
|
15
13
|
module ModelDivider
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
def self.divide(*models)
|
16
|
+
models.size > 1 ? models.each {|model| divide(model)} : require(locate(models))
|
17
|
+
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
protected
|
20
|
+
def self.locate(model)
|
21
|
+
File.join(File.dirname(__FILE__), "model", "#{model.to_s}")
|
22
|
+
end
|
25
23
|
|
26
24
|
end
|
27
25
|
|
data/spec/model/Account.rb
CHANGED
data/spec/model/Book.rb
CHANGED
data/spec/model/Friend.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class Friend
|
2
|
-
|
3
|
-
|
1
|
+
class Friend
|
2
|
+
include Zeng::Document
|
3
|
+
assign :name
|
4
4
|
end
|
data/spec/model/Icon.rb
CHANGED
data/spec/model/Project.rb
CHANGED
data/spec/model/User.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zeng
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Guimin Jiang
|
@@ -15,11 +15,11 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-04 00:00:00 +08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
22
|
+
name: json
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: "0"
|
33
33
|
type: :runtime
|
34
34
|
version_requirements: *id001
|
35
|
-
description:
|
35
|
+
description: " Zeng(\xE7\xBD\xBE) is a fishing tool\xEF\xBC\x8C it is target to capture data in nosql database\xE3\x80\x82\n"
|
36
36
|
email:
|
37
37
|
- kayak.jiang@gmail.com
|
38
38
|
executables: []
|
@@ -42,50 +42,29 @@ extensions: []
|
|
42
42
|
extra_rdoc_files: []
|
43
43
|
|
44
44
|
files:
|
45
|
-
- ./lib/cute_kv/timestamp.rb
|
46
|
-
- ./lib/cute_kv/serializers/json_serializer.rb
|
47
|
-
- ./lib/cute_kv/serializers/xml_serializer.rb
|
48
|
-
- ./lib/cute_kv/associations.rb
|
49
|
-
- ./lib/cute_kv/indexer.rb
|
50
|
-
- ./lib/cute_kv/connector.rb
|
51
|
-
- ./lib/cute_kv/serialization.rb
|
52
|
-
- ./lib/cute_kv/ext/string.rb
|
53
|
-
- ./lib/cute_kv/ext/symbol.rb
|
54
|
-
- ./lib/cute_kv/validations.rb
|
55
|
-
- ./lib/cute_kv/document.rb
|
56
|
-
- ./lib/cute_kv/adapters/tokyo_tyrant.rb
|
57
|
-
- ./lib/cute_kv/adapters/tokyo_cabinet.rb
|
58
|
-
- ./lib/cute_kv/adapters/light_cloud.rb
|
59
|
-
- ./lib/cutekv.rb
|
60
|
-
- ./tags
|
61
|
-
- ./CHANGE
|
62
|
-
- ./Rakefile
|
63
45
|
- ./MIT-LICENSE
|
64
|
-
- ./
|
65
|
-
- ./
|
66
|
-
- ./
|
46
|
+
- ./Rakefile
|
47
|
+
- ./TODOLIST
|
48
|
+
- ./CHANGE
|
49
|
+
- ./README.md
|
67
50
|
- ./spec/model/Icon.rb
|
68
|
-
- ./spec/model/Friend.rb
|
69
51
|
- ./spec/model/User.rb
|
70
|
-
- ./spec/model/
|
52
|
+
- ./spec/model/Friend.rb
|
53
|
+
- ./spec/model/Project.rb
|
71
54
|
- ./spec/model/Book.rb
|
72
55
|
- ./spec/model/Account.rb
|
73
|
-
- ./spec/case/timestamp_test.rb
|
74
|
-
- ./spec/case/validations_test.rb
|
75
|
-
- ./spec/case/symmetry_test.rb
|
76
|
-
- ./spec/case/sin_plu_dic_test.rb
|
77
|
-
- ./spec/case/serialization_test.rb
|
78
|
-
- ./spec/case/document_docking_test.rb
|
79
|
-
- ./spec/case/associations_test.rb
|
80
|
-
- ./spec/case/document_test.rb
|
81
|
-
- ./spec/case/indexer_test.rb
|
82
56
|
- ./spec/helper.rb
|
83
|
-
- ./spec/
|
84
|
-
- ./spec/
|
85
|
-
- ./
|
86
|
-
- ./
|
57
|
+
- ./spec/case/indexer_test.rb
|
58
|
+
- ./spec/case/document_test.rb
|
59
|
+
- ./lib/zeng.rb
|
60
|
+
- ./lib/zeng/indexer.rb
|
61
|
+
- ./lib/zeng/adapters/tokyo_tyrant.rb
|
62
|
+
- ./lib/zeng/adapters/tokyo_cabinet.rb
|
63
|
+
- ./lib/zeng/connector.rb
|
64
|
+
- ./lib/zeng/document.rb
|
65
|
+
- ./book.rb
|
87
66
|
has_rdoc: true
|
88
|
-
homepage:
|
67
|
+
homepage: https://github.com/baya/zeng
|
89
68
|
licenses: []
|
90
69
|
|
91
70
|
post_install_message:
|
@@ -98,12 +77,10 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
77
|
requirements:
|
99
78
|
- - ">="
|
100
79
|
- !ruby/object:Gem::Version
|
101
|
-
hash:
|
80
|
+
hash: 3
|
102
81
|
segments:
|
103
|
-
-
|
104
|
-
|
105
|
-
- 6
|
106
|
-
version: 1.8.6
|
82
|
+
- 0
|
83
|
+
version: "0"
|
107
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
85
|
none: false
|
109
86
|
requirements:
|
@@ -119,6 +96,6 @@ rubyforge_project:
|
|
119
96
|
rubygems_version: 1.3.7
|
120
97
|
signing_key:
|
121
98
|
specification_version: 3
|
122
|
-
summary:
|
99
|
+
summary: Zeng -- a data mapper tool for nosql database
|
123
100
|
test_files: []
|
124
101
|
|
data/README.rdoc
DELETED
@@ -1,89 +0,0 @@
|
|
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
|
-
|
@@ -1,22 +0,0 @@
|
|
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
|
@@ -1,22 +0,0 @@
|
|
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
|
data/lib/cute_kv/associations.rb
DELETED
@@ -1,285 +0,0 @@
|
|
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
|