thingtank 0.1.0 → 0.2.0
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 +24 -22
- data/Rakefile +1 -6
- data/VERSION +1 -1
- data/examples/bear_julius.rb +7 -7
- data/examples/first_marriage.rb +4 -4
- data/examples/immortal_julius.rb +2 -2
- data/examples/marriage_improvement.rb +11 -11
- data/examples/second_marriage.rb +2 -2
- data/lib/couchrest/extensions/view.rb +3 -3
- data/lib/thingtank/callbacks.rb +1 -1
- data/lib/thingtank/{role.rb → character.rb} +21 -21
- data/lib/thingtank/character_handling.rb +198 -0
- data/lib/thingtank/dependencies.rb +16 -16
- data/lib/thingtank/fakebase.rb +17 -17
- data/lib/thingtank/shared_methods.rb +19 -19
- data/lib/thingtank/shortcuts.rb +6 -6
- data/lib/thingtank/thingtank.rb +2 -2
- data/lib/thingtank.rb +9 -4
- data/test/test_fakebase.rb +115 -115
- data/test/test_helper.rb +4 -4
- data/test/test_thingtank.rb +17 -17
- data/test/test_views.rb +6 -6
- metadata +29 -29
- data/lib/thingtank/role_handling.rb +0 -198
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
thingtank:
|
2
|
-
|
1
|
+
thingtank: let couchrest docs have multiple characters at the same time
|
2
|
+
=======================================================================
|
3
|
+
|
4
|
+
[](https://secure.travis-ci.org/metakeule/thingtank)
|
3
5
|
|
4
6
|
ThingTank is a library that uses couchrest and couchrest model to create arbitrary
|
5
|
-
objects that may have
|
7
|
+
objects that may have multiple characters. The characters determine the
|
6
8
|
properties and they can be mixed and matched at will.
|
7
9
|
|
8
10
|
|
@@ -24,7 +26,7 @@ Examples:
|
|
24
26
|
|
25
27
|
Imagine a Caesar is born
|
26
28
|
|
27
|
-
class Born < ThingTank::
|
29
|
+
class Born < ThingTank::Character
|
28
30
|
property :birth_date, :alias => :born_at
|
29
31
|
property :birth_place
|
30
32
|
validates_presence_of :birth_date # make sure a date is given
|
@@ -32,7 +34,7 @@ Imagine a Caesar is born
|
|
32
34
|
|
33
35
|
just in case he might die....we might want to have a date and maybe even a place
|
34
36
|
|
35
|
-
class Dead < ThingTank::
|
37
|
+
class Dead < ThingTank::Character
|
36
38
|
property :date_of_death
|
37
39
|
property :place_of_death
|
38
40
|
validates_presence_of :date_of_death
|
@@ -40,7 +42,7 @@ just in case he might die....we might want to have a date and maybe even a place
|
|
40
42
|
|
41
43
|
and then he needs a name
|
42
44
|
|
43
|
-
class Person < ThingTank::
|
45
|
+
class Person < ThingTank::Character
|
44
46
|
property :name
|
45
47
|
property :gender
|
46
48
|
validates_presence_of :name
|
@@ -73,7 +75,7 @@ later...
|
|
73
75
|
when he is adult, he wants to marry. now things are getting a bit more complicated:
|
74
76
|
|
75
77
|
# he needs a marriage and a women
|
76
|
-
class Married < ThingTank::
|
78
|
+
class Married < ThingTank::Character
|
77
79
|
property :date # the date of the marriage
|
78
80
|
property :end # when the marriage ended
|
79
81
|
property :spouse # doc_id of the spouse
|
@@ -83,20 +85,20 @@ when he is adult, he wants to marry. now things are getting a bit more complicat
|
|
83
85
|
validate :spouse_should_be_a_person
|
84
86
|
# ensure that 'spouse' is a doc_id of a Person
|
85
87
|
def spouse_should_be_a_person
|
86
|
-
Person.get(self["spouse"]).valid? # loads doc as
|
88
|
+
Person.get(self["spouse"]).valid? # loads doc as character Person and validates, same as ThingTank.get(self["spouse"]).as(Person).valid?
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
90
92
|
we want easy access to the name of the spouse
|
91
93
|
|
92
|
-
class Spouse < ThingTank::
|
94
|
+
class Spouse < ThingTank::Character
|
93
95
|
property :married # doc must have "married" property (should be of class married, we don't check this at the moment)
|
94
96
|
property :married_state
|
95
97
|
|
96
98
|
validate :spouse_should_be_married
|
97
99
|
|
98
100
|
def married
|
99
|
-
self["married"] # contains a Married
|
101
|
+
self["married"] # contains a Married character
|
100
102
|
end
|
101
103
|
|
102
104
|
def spouse_should_be_married
|
@@ -118,10 +120,10 @@ we want easy access to the name of the spouse
|
|
118
120
|
|
119
121
|
now we could easily get julius married
|
120
122
|
|
121
|
-
conny = ThingTank.create :gender => "f", :name => 'Cornelia', :
|
123
|
+
conny = ThingTank.create :gender => "f", :name => 'Cornelia', :characters => ['Person']
|
122
124
|
julius["married"] = {"date" => "84 BC", "spouse" => conny.id}
|
123
125
|
julius["married_state"] = "married"
|
124
|
-
julius.with("married").is(Married).valid? # => true # "married" is a property that
|
126
|
+
julius.with("married").is(Married).valid? # => true # "married" is a property that has the Married character
|
125
127
|
julius.has(Spouse).valid? # #has is an alias of #is
|
126
128
|
julius.save
|
127
129
|
julius.reload
|
@@ -140,8 +142,8 @@ while that is nice, let see if we could make it more comfortable:
|
|
140
142
|
self["state"] = 'married'
|
141
143
|
_doc["married_state"] = 'married'
|
142
144
|
|
143
|
-
unless person["married"] && person.
|
144
|
-
person.
|
145
|
+
unless person["married"] && person.last_character(Married, "married").spouse == _doc["_id"]
|
146
|
+
person.add_character(Married, "married") do |m|
|
145
147
|
m.date = self["date"]
|
146
148
|
m.marry _doc
|
147
149
|
end
|
@@ -164,7 +166,7 @@ while that is nice, let see if we could make it more comfortable:
|
|
164
166
|
|
165
167
|
class Spouse
|
166
168
|
def married(&code)
|
167
|
-
_doc.
|
169
|
+
_doc.last_character Married, "married", &code
|
168
170
|
end
|
169
171
|
|
170
172
|
def divorce(date)
|
@@ -175,7 +177,7 @@ while that is nice, let see if we could make it more comfortable:
|
|
175
177
|
|
176
178
|
class Person
|
177
179
|
def marry(date, person)
|
178
|
-
_doc.
|
180
|
+
_doc.add_character Married, "married", do |m|
|
179
181
|
m.date = "84 BC"
|
180
182
|
m.marry person
|
181
183
|
end
|
@@ -189,7 +191,7 @@ it now becomes much less work and Cornelia also knows that she is married to Jul
|
|
189
191
|
julius.reload
|
190
192
|
julius.has(Spouse).name # => 'Cornelia'
|
191
193
|
julius.has(Spouse).married_state # => 'married'
|
192
|
-
conny_id = julius.
|
194
|
+
conny_id = julius.last_character(Married,"married").spouse
|
193
195
|
conny = ThingTank.get conny_id
|
194
196
|
conny.has(Spouse).married_state # => 'married'
|
195
197
|
|
@@ -211,10 +213,10 @@ julius is still married with Cornelia but he should not
|
|
211
213
|
if Cornelia died before his second marriage, it would not be a problem:
|
212
214
|
|
213
215
|
class Dead
|
214
|
-
# all callbacks of
|
216
|
+
# all callbacks of characters are called and defined like corresponding callbacks of the doc
|
215
217
|
before_save do
|
216
218
|
if _doc.is?(Spouse) && _doc['married_state'] == 'married'
|
217
|
-
Spouse.get(_doc.
|
219
|
+
Spouse.get(_doc.last_character(Married, 'married').spouse).widowed(self["date_of_death"])
|
218
220
|
end
|
219
221
|
true
|
220
222
|
end
|
@@ -259,14 +261,14 @@ if Cornelia died before his second marriage, it would not be a problem:
|
|
259
261
|
|
260
262
|
since julius is immortal, no one should be able to destroy him:
|
261
263
|
|
262
|
-
class Undestroyable < ThingTank::
|
264
|
+
class Undestroyable < ThingTank::Character
|
263
265
|
before_destroy do
|
264
266
|
false # never allow to destroy
|
265
267
|
end
|
266
268
|
end
|
267
269
|
|
268
270
|
julius.is(Undestroyable)
|
269
|
-
julius.save # save the
|
271
|
+
julius.save # save the character
|
270
272
|
|
271
273
|
id = julius.id
|
272
274
|
julius = ThingTank.get id
|
@@ -279,7 +281,7 @@ since julius is immortal, no one should be able to destroy him:
|
|
279
281
|
ThingTank.get(id).nil? # => julius is still there
|
280
282
|
|
281
283
|
You may subclass ThingTank to do further separation and mix the
|
282
|
-
native properties of ThingTanks / its subclasses with the
|
284
|
+
native properties of ThingTanks / its subclasses with the characters properties.
|
283
285
|
|
284
286
|
|
285
287
|
Contributing to thingtank
|
data/Rakefile
CHANGED
@@ -17,7 +17,7 @@ Jeweler::Tasks.new do |gem|
|
|
17
17
|
gem.name = "thingtank"
|
18
18
|
gem.homepage = "http://github.com/metakeule/thingtank"
|
19
19
|
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{
|
20
|
+
gem.summary = %Q{let couchrest docs have multiple characters at the same time}
|
21
21
|
gem.email = "Base64.decode64(bGludXhAbWFyY3JlbmVhcm5zLmRl\n)"
|
22
22
|
gem.authors = ["Marc Rene Arns"]
|
23
23
|
# dependencies defined in Gemfile
|
@@ -31,11 +31,6 @@ Rake::TestTask.new(:test) do |test|
|
|
31
31
|
test.verbose = true
|
32
32
|
end
|
33
33
|
|
34
|
-
desc "guard"
|
35
|
-
task :guard do
|
36
|
-
exec("bundle exec guard")
|
37
|
-
end
|
38
|
-
|
39
34
|
task :default => :test
|
40
35
|
|
41
36
|
require 'yard'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/examples/bear_julius.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class Born < ThingTank::
|
1
|
+
class Born < ThingTank::Character
|
2
2
|
property :birth_date, :alias => :born_at
|
3
3
|
property :birth_place
|
4
4
|
|
@@ -6,14 +6,14 @@ class Born < ThingTank::Role
|
|
6
6
|
end
|
7
7
|
|
8
8
|
# just in case he might die....we might want to have a date and maybe even a place
|
9
|
-
class Dead < ThingTank::
|
9
|
+
class Dead < ThingTank::Character
|
10
10
|
property :date_of_death
|
11
11
|
property :place_of_death
|
12
12
|
|
13
13
|
validates_presence_of :date_of_death
|
14
14
|
end
|
15
15
|
|
16
|
-
class Person < ThingTank::
|
16
|
+
class Person < ThingTank::Character
|
17
17
|
property :name
|
18
18
|
property :gender
|
19
19
|
|
@@ -40,10 +40,10 @@ def test_bear_julius
|
|
40
40
|
assert_equal 'Gaius Iulius Caesar', julius["name"]
|
41
41
|
assert_equal 'Rome', julius["birth_place"]
|
42
42
|
|
43
|
-
assert !julius["
|
44
|
-
assert_equal 2, julius["
|
45
|
-
assert julius["
|
46
|
-
assert julius["
|
43
|
+
assert !julius["characters"].nil?
|
44
|
+
assert_equal 2, julius["characters"].size
|
45
|
+
assert julius["characters"].include? Person.to_s
|
46
|
+
assert julius["characters"].include? Born.to_s
|
47
47
|
assert_equal "100 BC", julius.is(Born).born_at
|
48
48
|
|
49
49
|
return julius
|
data/examples/first_marriage.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative 'bear_julius.rb'
|
2
2
|
|
3
3
|
# he needs a marriage and a women
|
4
|
-
class Married < ThingTank::
|
4
|
+
class Married < ThingTank::Character
|
5
5
|
property :date # the date of the marriage
|
6
6
|
property :end # when the marriage ended
|
7
7
|
property :spouse # doc_id of the spouse
|
@@ -18,7 +18,7 @@ class Married < ThingTank::Role
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# we want easy access to the name of the spouse
|
21
|
-
class Spouse < ThingTank::
|
21
|
+
class Spouse < ThingTank::Character
|
22
22
|
property :married
|
23
23
|
property :married_state
|
24
24
|
|
@@ -47,7 +47,7 @@ end
|
|
47
47
|
|
48
48
|
def test_first_marriage()
|
49
49
|
julius = test_bear_julius
|
50
|
-
conny = create :gender => "f", :name => 'Cornelia', :
|
50
|
+
conny = create :gender => "f", :name => 'Cornelia', :characters => ['Person']
|
51
51
|
|
52
52
|
julius["married"] = {"date" => "84 BC", "spouse" => conny.id}
|
53
53
|
julius["married_state"] = "married"
|
@@ -65,7 +65,7 @@ end
|
|
65
65
|
|
66
66
|
def test_first_marriage_shortcuts()
|
67
67
|
julius = test_bear_julius
|
68
|
-
conny = create :gender => "f", :name => 'Cornelia', :
|
68
|
+
conny = create :gender => "f", :name => 'Cornelia', :characters => ['Person']
|
69
69
|
|
70
70
|
julius["married"] = {"date" => "84 BC", "spouse" => conny.id}
|
71
71
|
julius["married_state"] = "married"
|
data/examples/immortal_julius.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative 'bear_julius.rb'
|
2
2
|
|
3
|
-
class Undestroyable < ThingTank::
|
3
|
+
class Undestroyable < ThingTank::Character
|
4
4
|
before_destroy do
|
5
5
|
false # never allow to destroy
|
6
6
|
end
|
@@ -9,7 +9,7 @@ end
|
|
9
9
|
def test_julius_immortal
|
10
10
|
julius = test_bear_julius()
|
11
11
|
julius.is(Undestroyable)
|
12
|
-
julius.save # save the
|
12
|
+
julius.save # save the character
|
13
13
|
|
14
14
|
id = julius.id
|
15
15
|
julius = db_load id
|
@@ -12,8 +12,8 @@ class Married
|
|
12
12
|
self["state"] = 'married'
|
13
13
|
_doc["married_state"] = 'married'
|
14
14
|
|
15
|
-
unless person["married"] && person.
|
16
|
-
person.
|
15
|
+
unless person["married"] && person.last_character(Married, "married").spouse == _doc["_id"]
|
16
|
+
person.add_character(Married, "married") do |m|
|
17
17
|
m.date = self["date"]
|
18
18
|
m.marry _doc
|
19
19
|
end
|
@@ -36,7 +36,7 @@ end
|
|
36
36
|
|
37
37
|
class Spouse
|
38
38
|
def married(&code)
|
39
|
-
_doc.
|
39
|
+
_doc.last_character Married, "married", &code
|
40
40
|
end
|
41
41
|
|
42
42
|
def divorce(date)
|
@@ -47,7 +47,7 @@ end
|
|
47
47
|
|
48
48
|
class Person
|
49
49
|
def marry(date, person)
|
50
|
-
_doc.
|
50
|
+
_doc.add_character Married, "married" do |m|
|
51
51
|
m.date = "84 BC"
|
52
52
|
m.marry person
|
53
53
|
end
|
@@ -64,13 +64,13 @@ def test_improved_marriage()
|
|
64
64
|
assert_equal 'Cornelia', julius.has(Spouse).name
|
65
65
|
assert_equal 'married', julius.has(Spouse).married_state
|
66
66
|
|
67
|
-
conny = db_load julius.
|
67
|
+
conny = db_load julius.last_character(Married,"married").spouse
|
68
68
|
|
69
69
|
assert_equal 'Gaius Iulius Caesar', conny.has(Spouse).name
|
70
70
|
assert_equal 'married', conny.has(Spouse).married_state
|
71
71
|
|
72
|
-
assert_equal julius['_id'], conny.
|
73
|
-
assert_equal "84 BC", conny.
|
72
|
+
assert_equal julius['_id'], conny.last_character(Married,"married").spouse
|
73
|
+
assert_equal "84 BC", conny.last_character(Married,"married").date
|
74
74
|
|
75
75
|
return julius
|
76
76
|
end
|
@@ -85,16 +85,16 @@ def test_improved_marriage_divorce()
|
|
85
85
|
assert_equal nil, julius.has(Spouse).name
|
86
86
|
assert_equal 'Cornelia', julius.has(Spouse).ex
|
87
87
|
assert_equal 'divorced', julius["married_state"]
|
88
|
-
assert_equal "85 BC", julius.
|
88
|
+
assert_equal "85 BC", julius.last_character(Married,"married").end
|
89
89
|
|
90
|
-
conny = db_load julius.
|
90
|
+
conny = db_load julius.last_character(Married,"married").spouse
|
91
91
|
|
92
92
|
assert_equal nil, conny.has(Spouse).name
|
93
93
|
assert_equal 'Gaius Iulius Caesar', conny.has(Spouse).ex
|
94
94
|
assert_equal 'divorced', conny["married_state"]
|
95
95
|
|
96
|
-
assert_equal julius['_id'], conny.
|
97
|
-
assert_equal "85 BC", conny.
|
96
|
+
assert_equal julius['_id'], conny.last_character(Married,"married").spouse
|
97
|
+
assert_equal "85 BC", conny.last_character(Married,"married").end
|
98
98
|
return julius
|
99
99
|
end
|
100
100
|
|
data/examples/second_marriage.rb
CHANGED
@@ -2,10 +2,10 @@ require_relative 'marriage_improvement.rb'
|
|
2
2
|
|
3
3
|
class Dead
|
4
4
|
|
5
|
-
# all callbacks of
|
5
|
+
# all callbacks of characters are called and defined like corresponding callbacks of the doc
|
6
6
|
before_save do
|
7
7
|
if _doc.is?(Spouse) && _doc['married_state'] == 'married'
|
8
|
-
Spouse.get(_doc.
|
8
|
+
Spouse.get(_doc.last_character(Married, 'married').spouse).widowed(self["date_of_death"])
|
9
9
|
end
|
10
10
|
true
|
11
11
|
end
|
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
class CouchRest::Model::Designs::DesignMapper
|
4
4
|
|
5
|
-
# generate a view to show only ThingTanks of a certain
|
6
|
-
def
|
5
|
+
# generate a view to show only ThingTanks of a certain character, define them all in a ThingTank subclass (not in a character)
|
6
|
+
def character_view(klass, name, opts={})
|
7
7
|
name = "#{klass.to_s.downcase}_#{name}"
|
8
8
|
opts ||= {}
|
9
9
|
opts[:guards] ||= []
|
10
10
|
# there is no "inArray" like function in couchdb, see http://stackoverflow.com/questions/3740464/i-have-to-write-every-function-i-need-for-couchdb
|
11
|
-
opts[:guards] << "((doc['
|
11
|
+
opts[:guards] << "((doc['characters'] !== undefined) && (function (item,arr) { for(p=0;p<arr.length;p++) if (item == arr[p]) return true; return false;})('#{klass.to_s}',doc['characters']))"
|
12
12
|
view(name, opts)
|
13
13
|
end
|
14
14
|
|
data/lib/thingtank/callbacks.rb
CHANGED
@@ -18,7 +18,7 @@ class ThingTank
|
|
18
18
|
# mimic the destroy_document method from https://github.com/langalex/couch_potato/blob/master/lib/couch_potato/database.rb
|
19
19
|
before_destroy do
|
20
20
|
ok = true
|
21
|
-
(self["
|
21
|
+
(self["characters"] || []).each do |klass|
|
22
22
|
document = self.as(klass.constantize)
|
23
23
|
(ok = false) if false == document.run_callbacks(:destroy) do
|
24
24
|
true
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
class ThingTank
|
3
3
|
|
4
|
-
class
|
4
|
+
class Character < CouchRest::Model::Base
|
5
5
|
|
6
6
|
include ThingTank::ForceUpdate
|
7
7
|
include ThingTank::SharedMethods
|
@@ -9,13 +9,13 @@ class ThingTank
|
|
9
9
|
class << self
|
10
10
|
|
11
11
|
def property(name, *args)
|
12
|
-
@
|
13
|
-
@
|
12
|
+
@character_properties ||= []
|
13
|
+
@character_properties << name.to_s
|
14
14
|
super
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
@
|
17
|
+
def character_properties
|
18
|
+
@character_properties
|
19
19
|
end
|
20
20
|
|
21
21
|
def -(key)
|
@@ -25,12 +25,12 @@ class ThingTank
|
|
25
25
|
def get(id, db = database)
|
26
26
|
doc = ThingTank.get(id)
|
27
27
|
return nil if doc.nil?
|
28
|
-
return doc.
|
28
|
+
return doc.to_character(self)
|
29
29
|
end
|
30
30
|
|
31
31
|
def get!(id, db = database)
|
32
32
|
doc = ThingTank.get!(id)
|
33
|
-
doc.
|
33
|
+
doc.to_character(self)
|
34
34
|
end
|
35
35
|
|
36
36
|
def wants(*modules)
|
@@ -43,11 +43,11 @@ class ThingTank
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def design
|
46
|
-
raise "design is not supported in ThingTank::
|
46
|
+
raise "design is not supported in ThingTank::Character, please use the 'character_view' method in a ThingTank subclass design definition"
|
47
47
|
end
|
48
48
|
|
49
49
|
def view_by(*args)
|
50
|
-
raise "view_by is not supported in ThingTank::
|
50
|
+
raise "view_by is not supported in ThingTank::Character, please use the 'character_view_by' method in a ThingTank subclass"
|
51
51
|
end
|
52
52
|
|
53
53
|
end
|
@@ -65,9 +65,9 @@ class ThingTank
|
|
65
65
|
end
|
66
66
|
|
67
67
|
# the virtual _doc that contains me, you should not need it normally
|
68
|
-
def
|
68
|
+
def _character_doc
|
69
69
|
if database.is_a?(FakeBase)
|
70
|
-
database.
|
70
|
+
database._character_doc
|
71
71
|
else
|
72
72
|
nil
|
73
73
|
end
|
@@ -75,35 +75,35 @@ class ThingTank
|
|
75
75
|
|
76
76
|
def flush_to_doc
|
77
77
|
if changed?
|
78
|
-
|
79
|
-
|
78
|
+
changed_to_character_hash().each do |k,v|
|
79
|
+
_character_doc[k] = v
|
80
80
|
end
|
81
|
-
|
81
|
+
_character_doc.save
|
82
82
|
@changed_attributes.clear
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
86
|
def reload
|
87
|
-
attrs =
|
87
|
+
attrs = _character_doc.as(self.class).to_character_hash
|
88
88
|
prepare_all_attributes(attrs, :directly_set_attributes => true)
|
89
89
|
@changed_attributes.clear
|
90
90
|
self
|
91
91
|
end
|
92
92
|
|
93
|
-
def
|
94
|
-
|
93
|
+
def to_character(klass, key, &code)
|
94
|
+
_character_doc.to_character(klass, key, &code)
|
95
95
|
end
|
96
96
|
|
97
97
|
def first(key)
|
98
|
-
|
98
|
+
_character_doc.first(key)
|
99
99
|
end
|
100
100
|
|
101
101
|
def last(key)
|
102
|
-
|
102
|
+
_character_doc.last(key)
|
103
103
|
end
|
104
104
|
|
105
|
-
def
|
106
|
-
|
105
|
+
def add_character(klass, key=nil, &code)
|
106
|
+
_character_doc.add_character(klass, key, &code)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|