scout-gear 10.4.0 → 10.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +100 -656
  3. data/Rakefile +1 -0
  4. data/VERSION +1 -1
  5. data/bin/scout +1 -3
  6. data/lib/scout/association/fields.rb +170 -0
  7. data/lib/scout/association/index.rb +229 -0
  8. data/lib/scout/association/item.rb +227 -0
  9. data/lib/scout/association/util.rb +7 -0
  10. data/lib/scout/association.rb +100 -0
  11. data/lib/scout/entity/format.rb +62 -0
  12. data/lib/scout/entity/identifiers.rb +111 -0
  13. data/lib/scout/entity/object.rb +20 -0
  14. data/lib/scout/entity/property.rb +165 -0
  15. data/lib/scout/entity.rb +40 -0
  16. data/lib/scout/offsite/step.rb +2 -2
  17. data/lib/scout/{tsv/persist → persist/engine}/fix_width_table.rb +25 -33
  18. data/lib/scout/persist/engine/packed_index.rb +100 -0
  19. data/lib/scout/persist/engine/sharder.rb +219 -0
  20. data/lib/scout/{tsv/persist → persist/engine}/tkrzw.rb +0 -17
  21. data/lib/scout/{tsv/persist → persist/engine}/tokyocabinet.rb +55 -31
  22. data/lib/scout/persist/engine.rb +4 -0
  23. data/lib/scout/{tsv/persist/adapter.rb → persist/tsv/adapter/base.rb} +80 -51
  24. data/lib/scout/persist/tsv/adapter/fix_width_table.rb +106 -0
  25. data/lib/scout/persist/tsv/adapter/packed_index.rb +95 -0
  26. data/lib/scout/persist/tsv/adapter/sharder.rb +54 -0
  27. data/lib/scout/persist/tsv/adapter/tkrzw.rb +18 -0
  28. data/lib/scout/persist/tsv/adapter/tokyocabinet.rb +65 -0
  29. data/lib/scout/persist/tsv/adapter.rb +6 -0
  30. data/lib/scout/{tsv/persist → persist/tsv}/serialize.rb +5 -0
  31. data/lib/scout/persist/tsv.rb +107 -0
  32. data/lib/scout/tsv/annotation/repo.rb +83 -0
  33. data/lib/scout/tsv/annotation.rb +169 -0
  34. data/lib/scout/tsv/attach.rb +95 -19
  35. data/lib/scout/tsv/change_id/translate.rb +148 -0
  36. data/lib/scout/tsv/change_id.rb +3 -0
  37. data/lib/scout/tsv/csv.rb +85 -0
  38. data/lib/scout/tsv/dumper.rb +113 -25
  39. data/lib/scout/tsv/entity.rb +5 -0
  40. data/lib/scout/tsv/index.rb +88 -36
  41. data/lib/scout/tsv/open.rb +21 -8
  42. data/lib/scout/tsv/parser.rb +153 -90
  43. data/lib/scout/tsv/path.rb +7 -2
  44. data/lib/scout/tsv/stream.rb +48 -6
  45. data/lib/scout/tsv/transformer.rb +4 -3
  46. data/lib/scout/tsv/traverse.rb +26 -18
  47. data/lib/scout/tsv/util/process.rb +7 -0
  48. data/lib/scout/tsv/util/reorder.rb +25 -15
  49. data/lib/scout/tsv/util/select.rb +9 -1
  50. data/lib/scout/tsv/util/sort.rb +90 -2
  51. data/lib/scout/tsv/util/unzip.rb +56 -0
  52. data/lib/scout/tsv/util.rb +52 -5
  53. data/lib/scout/tsv.rb +45 -27
  54. data/lib/scout/work_queue/socket.rb +8 -0
  55. data/lib/scout/work_queue/worker.rb +22 -5
  56. data/lib/scout/work_queue.rb +38 -24
  57. data/lib/scout/workflow/definition.rb +11 -10
  58. data/lib/scout/workflow/deployment/orchestrator.rb +20 -3
  59. data/lib/scout/workflow/deployment/trace.rb +205 -0
  60. data/lib/scout/workflow/deployment.rb +1 -0
  61. data/lib/scout/workflow/documentation.rb +1 -1
  62. data/lib/scout/workflow/step/archive.rb +42 -0
  63. data/lib/scout/workflow/step/children.rb +51 -0
  64. data/lib/scout/workflow/step/config.rb +1 -1
  65. data/lib/scout/workflow/step/dependencies.rb +24 -7
  66. data/lib/scout/workflow/step/file.rb +19 -0
  67. data/lib/scout/workflow/step/info.rb +37 -9
  68. data/lib/scout/workflow/step/progress.rb +11 -2
  69. data/lib/scout/workflow/step/status.rb +8 -1
  70. data/lib/scout/workflow/step.rb +80 -25
  71. data/lib/scout/workflow/task/dependencies.rb +4 -1
  72. data/lib/scout/workflow/task/inputs.rb +91 -41
  73. data/lib/scout/workflow/task.rb +54 -57
  74. data/lib/scout/workflow/usage.rb +1 -1
  75. data/lib/scout/workflow/util.rb +4 -0
  76. data/lib/scout/workflow.rb +110 -13
  77. data/lib/scout-gear.rb +2 -0
  78. data/lib/scout.rb +0 -1
  79. data/scout-gear.gemspec +80 -23
  80. data/scout_commands/rbbt +2 -0
  81. data/test/data/person/brothers +4 -0
  82. data/test/data/person/identifiers +10 -0
  83. data/test/data/person/marriages +3 -0
  84. data/test/data/person/parents +6 -0
  85. data/test/scout/association/test_fields.rb +105 -0
  86. data/test/scout/association/test_index.rb +70 -0
  87. data/test/scout/association/test_item.rb +21 -0
  88. data/test/scout/entity/test_format.rb +19 -0
  89. data/test/scout/entity/test_identifiers.rb +58 -0
  90. data/test/scout/entity/test_object.rb +0 -0
  91. data/test/scout/entity/test_property.rb +345 -0
  92. data/test/scout/{tsv/persist → persist/engine}/test_fix_width_table.rb +0 -1
  93. data/test/scout/persist/engine/test_packed_index.rb +99 -0
  94. data/test/scout/persist/engine/test_sharder.rb +31 -0
  95. data/test/scout/persist/engine/test_tkrzw.rb +0 -0
  96. data/test/scout/persist/engine/test_tokyocabinet.rb +17 -0
  97. data/test/scout/persist/test_tsv.rb +146 -0
  98. data/test/scout/{tsv/persist/test_adapter.rb → persist/tsv/adapter/test_base.rb} +3 -4
  99. data/test/scout/persist/tsv/adapter/test_fix_width_table.rb +46 -0
  100. data/test/scout/persist/tsv/adapter/test_packed_index.rb +37 -0
  101. data/test/scout/persist/tsv/adapter/test_serialize.rb +0 -0
  102. data/test/scout/persist/tsv/adapter/test_sharder.rb +290 -0
  103. data/test/scout/{tsv/persist → persist/tsv/adapter}/test_tkrzw.rb +3 -6
  104. data/test/scout/persist/tsv/adapter/test_tokyocabinet.rb +282 -0
  105. data/test/scout/persist/tsv/test_serialize.rb +12 -0
  106. data/test/scout/test_association.rb +51 -0
  107. data/test/scout/test_entity.rb +40 -0
  108. data/test/scout/test_tsv.rb +33 -4
  109. data/test/scout/test_work_queue.rb +3 -2
  110. data/test/scout/test_workflow.rb +16 -15
  111. data/test/scout/tsv/annotation/test_repo.rb +150 -0
  112. data/test/scout/tsv/change_id/test_translate.rb +178 -0
  113. data/test/scout/tsv/test_annotation.rb +52 -0
  114. data/test/scout/tsv/test_attach.rb +226 -1
  115. data/test/scout/tsv/test_change_id.rb +25 -0
  116. data/test/scout/tsv/test_csv.rb +50 -0
  117. data/test/scout/tsv/test_dumper.rb +38 -0
  118. data/test/scout/tsv/test_entity.rb +0 -0
  119. data/test/scout/tsv/test_index.rb +82 -0
  120. data/test/scout/tsv/test_open.rb +44 -0
  121. data/test/scout/tsv/test_parser.rb +70 -0
  122. data/test/scout/tsv/test_stream.rb +22 -0
  123. data/test/scout/tsv/test_transformer.rb +27 -3
  124. data/test/scout/tsv/test_traverse.rb +78 -0
  125. data/test/scout/tsv/util/test_process.rb +16 -0
  126. data/test/scout/tsv/util/test_reorder.rb +67 -0
  127. data/test/scout/tsv/util/test_sort.rb +28 -1
  128. data/test/scout/tsv/util/test_unzip.rb +32 -0
  129. data/test/scout/work_queue/test_socket.rb +4 -1
  130. data/test/scout/workflow/deployment/test_orchestrator.rb +17 -26
  131. data/test/scout/workflow/deployment/test_trace.rb +25 -0
  132. data/test/scout/workflow/step/test_archive.rb +28 -0
  133. data/test/scout/workflow/step/test_children.rb +25 -0
  134. data/test/scout/workflow/step/test_info.rb +16 -0
  135. data/test/scout/workflow/task/test_dependencies.rb +16 -16
  136. data/test/scout/workflow/task/test_inputs.rb +45 -1
  137. data/test/scout/workflow/test_definition.rb +52 -0
  138. data/test/scout/workflow/test_step.rb +57 -0
  139. data/test/scout/workflow/test_task.rb +26 -1
  140. data/test/scout/workflow/test_usage.rb +4 -4
  141. data/test/test_helper.rb +23 -1
  142. metadata +71 -14
  143. data/lib/scout/tsv/persist.rb +0 -27
  144. data/test/scout/tsv/persist/test_tokyocabinet.rb +0 -120
  145. data/test/scout/tsv/test_persist.rb +0 -45
@@ -0,0 +1,100 @@
1
+ class PackedIndex
2
+ attr_accessor :persistence_path, :mask, :mask_length, :offset, :item_size, :stream, :nil_string
3
+
4
+ ELEMS = {
5
+ "i" => ["l", 4],
6
+ "I" => ["q", 8],
7
+ "f" => ["f", 4],
8
+ "F" => ["d", 8],
9
+ }
10
+
11
+ def self.process_mask(mask)
12
+ str = ""
13
+ size = 0
14
+ mask.each do |e|
15
+ if ELEMS.include? e
16
+ str << ELEMS[e][0]
17
+ size += ELEMS[e][1]
18
+ elsif e =~ /^(\d+)s$/
19
+ num = $1.to_i
20
+ str << "a" << num.to_s
21
+ size += num
22
+ else
23
+ e, num = e.split(":")
24
+ str << e
25
+ size = (num.nil? ? size + 1 : size + num.to_i)
26
+ end
27
+ end
28
+ [str, size]
29
+ end
30
+
31
+ def size
32
+ @size ||= begin
33
+ (File.size(persistence_path) - offset) / item_size
34
+ end
35
+ end
36
+
37
+ def initialize(persistence_path, write = false, pattern = nil)
38
+ @persistence_path = persistence_path
39
+ if write
40
+ @stream = Open.open(persistence_path, :mode => 'wb')
41
+ @mask, @item_size = PackedIndex.process_mask pattern
42
+ header = [@mask.length, @item_size].pack("ll")
43
+ @stream.write(header)
44
+ @stream.write(mask)
45
+ @offset = @mask.length + 8
46
+ else
47
+ @stream = Open.open(persistence_path, :mode => 'rb')
48
+ header = @stream.read(8)
49
+ mask_length, @item_size = header.unpack("ll")
50
+ @mask = @stream.read(mask_length)
51
+ @offset = @mask.length + 8
52
+ end
53
+ @nil_string = "NIL" << ("-" * (@item_size - 3))
54
+ end
55
+
56
+ def file
57
+ @persistence_path
58
+ end
59
+
60
+ def close
61
+ @stream.close
62
+ end
63
+
64
+ def write(force = false)
65
+ close
66
+ @stream = Open.open(persistence_path, :mode => 'wb')
67
+ end
68
+
69
+ def read(force = false)
70
+ close
71
+ @stream = Open.open(persistence_path, :mode => 'rb')
72
+ end
73
+
74
+ def <<(payload)
75
+ if payload.nil?
76
+ @stream.write nil_string
77
+ else
78
+ @stream.write payload.pack(mask)
79
+ end
80
+ end
81
+
82
+ def get_position(position)
83
+ @stream.seek(position * item_size + offset)
84
+ encoded = @stream.read(item_size)
85
+ return nil if encoded.nil? or encoded == nil_string
86
+ encoded.unpack mask
87
+ end
88
+
89
+ alias [] get_position
90
+
91
+ def values_at(*positions)
92
+ positions.collect{|p|
93
+ get_position[p]
94
+ }
95
+ end
96
+
97
+ def close
98
+ @stream.close unless @stream.closed?
99
+ end
100
+ end
@@ -0,0 +1,219 @@
1
+ class Sharder
2
+ attr_accessor :persistence_path, :shard_function, :databases, :closed, :writable, :mutex, :db_type, :persist_options
3
+
4
+ def initialize(persistence_path, write=false, db_type=nil, persist_options={}, &block)
5
+ @shard_function = persist_options[:shard_function] || block
6
+ @persist_options = persist_options
7
+ @persistence_path = Path.setup(persistence_path)
8
+ @mutex = Mutex.new
9
+ @writable = write
10
+ @db_type = db_type
11
+
12
+ if write
13
+ @databases = {}
14
+ end
15
+ end
16
+
17
+ def persistence_path=(path)
18
+ @persistence_path = path
19
+ databases.values.each{|db| db.persistence_path = File.join(path, File.basename(db.persistence_path))}
20
+ end
21
+
22
+ def databases
23
+ @databases ||= begin
24
+ hash = {}
25
+ @persistence_path.glob('shard-*').each do |f|
26
+ next if f.end_with?('.metadata')
27
+ shard = File.basename(f).match(/shard-(.*)/)[1]
28
+ hash[shard] = Persist.open_database(f, false, :clean, db_type, @persist_options)
29
+ end
30
+ hash
31
+ end
32
+ end
33
+
34
+ def database(key)
35
+ shard = shard_function.call(key)
36
+ if databases.include? shard
37
+ databases[shard]
38
+ else
39
+ database = databases[shard] ||= begin
40
+ path = File.join(persistence_path, 'shard-' << shard.to_s)
41
+ (writable or File.exist?(path)) ? Persist.open_database(path, (File.exist?(path) ? false : writable), :clean, db_type, @persist_options) : nil
42
+ end
43
+ Log.warn "Database #{ path } missing" if database.nil?
44
+ database
45
+ end
46
+ end
47
+
48
+ MAX_CHAR = 255.chr
49
+
50
+ def prefix(key)
51
+ range(key, 1, key + MAX_CHAR, 1)
52
+ end
53
+
54
+ def get_prefix(key)
55
+ keys = prefix(key)
56
+ select(:key => keys)
57
+ end
58
+
59
+ def closed?
60
+ @closed
61
+ end
62
+
63
+ def close
64
+ @closed = true
65
+ super
66
+ end
67
+
68
+ def read(force = false)
69
+ raise "SIOT"
70
+ return if not write? and not closed and not force
71
+ self.close
72
+ databases.each{|d| d.read }
73
+ @writable = false
74
+ @closed = false
75
+ self
76
+ end
77
+
78
+ def write(force = true)
79
+ return if write? and not closed and not force
80
+ self.close
81
+
82
+ databases.each{|d| d.write }
83
+
84
+ @writable = true
85
+ @closed = false
86
+ self
87
+ end
88
+
89
+ def write?
90
+ @writable
91
+ end
92
+
93
+ def read?
94
+ ! write?
95
+ end
96
+
97
+ def range(*args)
98
+ databases.values.inject([]) do |acc,database|
99
+ acc.concat database.range(*args) if TokyoCabinet::BDB === database
100
+ acc
101
+ end
102
+ end
103
+
104
+ def each
105
+ databases.values.each do |database|
106
+ database.each do |k,v|
107
+ yield k, v
108
+ end
109
+ end
110
+ end
111
+
112
+ def include?(key)
113
+ self[key] != nil
114
+ end
115
+
116
+ def collect
117
+ res = []
118
+ each do |key, value|
119
+ res << if block_given?
120
+ yield key, value
121
+ else
122
+ [key, value]
123
+ end
124
+ end
125
+ res
126
+ end
127
+
128
+ def write_and_read
129
+ lock_filename = Persist.persistence_path(File.join(persistence_path, 'write'), {:dir => TSV.lock_dir})
130
+ Misc.lock(lock_filename) do
131
+ @mutex.synchronize do
132
+ write if @closed or not write?
133
+ res = begin
134
+ yield
135
+ ensure
136
+ read
137
+ end
138
+ res
139
+ end
140
+ end
141
+ end
142
+
143
+ def write_and_close
144
+ lock_filename = Persist.persistence_path(File.join(persistence_path, 'write'), {:dir => TSV.lock_dir})
145
+ Misc.lock(lock_filename) do
146
+ @mutex.synchronize do
147
+ write if @closed or not write?
148
+ res = begin
149
+ yield
150
+ ensure
151
+ close
152
+ end
153
+ res
154
+ end
155
+ end
156
+ end
157
+
158
+ def read_and_close
159
+ @mutex.synchronize do
160
+ read if @closed or not read?
161
+ res = begin
162
+ yield
163
+ ensure
164
+ close
165
+ end
166
+ res
167
+ end
168
+ end
169
+
170
+ def merge!(hash)
171
+ hash.each do |key,values|
172
+ self[key] = values
173
+ end
174
+ end
175
+
176
+ def keys
177
+ databases.values.collect{|d| d.keys }
178
+ end
179
+
180
+ def []=(key, value, clean = false)
181
+ database(key).send(:[]=, key, value)
182
+ end
183
+
184
+ def [](key, clean=false)
185
+ database = database(key)
186
+ return nil if database.nil?
187
+ database.send(:[], key)
188
+ end
189
+
190
+ #def <<(p)
191
+ # return if p.nil?
192
+ # self[p.first] = p.last
193
+ #end
194
+
195
+ def <<(values)
196
+ key, rest = values
197
+ database(key) << values
198
+ end
199
+
200
+ def write
201
+ databases.values.each{|database| database.write }
202
+ end
203
+
204
+ def read(force = false)
205
+ databases.values.each{|database| database.read(force) }
206
+ end
207
+
208
+ def close
209
+ databases.values.each{|database| database.close }
210
+ end
211
+
212
+ def size
213
+ databases.inject(0){|acc,i|
214
+ shard, db = i;
215
+ acc += db.size
216
+ }
217
+ end
218
+ end
219
+
@@ -1,5 +1,4 @@
1
1
  require 'tkrzw'
2
- require_relative 'adapter'
3
2
 
4
3
  module ScoutTKRZW
5
4
  attr_accessor :persistence_path, :persistence_class, :open_options
@@ -66,19 +65,3 @@ module ScoutTKRZW
66
65
  search("contain", "")
67
66
  end
68
67
  end
69
-
70
- Persist.save_drivers[:tkh] = proc do |file, content|
71
- data = ScoutTKRZW.open(file, true, "tkh")
72
- content.annotate(data)
73
- data.extend TSVAdapter
74
- data.merge!(content)
75
- data.close
76
- data.read
77
- data
78
- end
79
-
80
- Persist.load_drivers[:tkh] = proc do |file|
81
- data = ScoutTKRZW.open(file, false, "tkh")
82
- data.extend TSVAdapter unless TSVAdapter === data
83
- data
84
- end
@@ -1,10 +1,9 @@
1
1
  require 'tokyocabinet'
2
- require_relative 'adapter'
3
2
 
4
3
  module ScoutCabinet
5
4
  attr_accessor :persistence_path, :persistence_class
6
5
 
7
- def self.open(path, write, tokyocabinet_class = TokyoCabinet::HDB)
6
+ def self.open(path, write = true, tokyocabinet_class = TokyoCabinet::HDB)
8
7
  path = path.find if Path === path
9
8
  if String === tokyocabinet_class && tokyocabinet_class.include?(":big")
10
9
  big = true
@@ -25,7 +24,7 @@ module ScoutCabinet
25
24
  database = Log.ignore_stderr do Persist::CONNECTIONS[path] ||= tokyocabinet_class.new end
26
25
 
27
26
  if big and not Open.exists?(path)
28
- database.tune(nil,nil,nil,tokyocabinet_class::TLARGE | tokyocabinet_class::TDEFLATE)
27
+ database.tune(nil, nil, nil, tokyocabinet_class::TLARGE | tokyocabinet_class::TDEFLATE)
29
28
  end
30
29
 
31
30
  flags = (write ? tokyocabinet_class::OWRITER | tokyocabinet_class::OCREAT : tokyocabinet_class::OREADER)
@@ -56,7 +55,7 @@ module ScoutCabinet
56
55
  end
57
56
 
58
57
  def read(force = false)
59
- return if ! write? && ! closed && ! force
58
+ return if ! @writable && ! @closed && ! force
60
59
  self.close
61
60
  if !self.open(@persistence_path, persistence_class::OREADER)
62
61
  ecode = self.ecode
@@ -69,8 +68,17 @@ module ScoutCabinet
69
68
  self
70
69
  end
71
70
 
71
+ def write?
72
+ @writable
73
+ end
74
+
75
+ def closed?
76
+ @closed
77
+ end
78
+
79
+
72
80
  def write(force = true)
73
- return if write? && ! closed && ! force
81
+ return if write? && ! closed? && ! force
74
82
  self.close
75
83
 
76
84
  if !self.open(@persistence_path, persistence_class::OWRITER)
@@ -84,35 +92,51 @@ module ScoutCabinet
84
92
  self
85
93
  end
86
94
 
87
- #def self.open_tokyocabinet(path, write, serializer = nil, tokyocabinet_class = TokyoCabinet::HDB)
88
- # raise
89
- # write = true unless File.exist? path
90
-
91
- # FileUtils.mkdir_p File.dirname(path) unless File.exist?(File.dirname(path))
95
+ def write_and_read
96
+ begin
97
+ write
98
+ yield
99
+ ensure
100
+ read
101
+ end
102
+ end
92
103
 
93
- # database = Persist::TCAdapter.open(path, write, tokyocabinet_class)
104
+ def write_and_close
105
+ begin
106
+ write
107
+ yield
108
+ ensure
109
+ close
110
+ end
111
+ end
94
112
 
95
- # unless serializer == :clean
96
- # TSV.setup database
97
- # database.write_and_read do
98
- # database.serializer = serializer
99
- # end if serializer && database.serializer != serializer
100
- # end
113
+ def self.importtsv(database, stream)
114
+ begin
115
+ bin = case database
116
+ when TokyoCabinet::HDB
117
+ 'tchmgr'
118
+ when TokyoCabinet::BDB
119
+ 'tcbmgr'
120
+ else
121
+ raise "Database not HDB or BDB: #{Log.fingerprint database}"
122
+ end
123
+
124
+ database.close
125
+ CMD.cmd("#{bin} version", :log => false)
126
+ FileUtils.mkdir_p File.dirname(database.persistence_path)
127
+ CMD.cmd("#{bin} importtsv '#{database.persistence_path}'", :in => stream, :log => false, :dont_close_in => true)
128
+ rescue
129
+ Log.debug("tchmgr importtsv failed for: #{database.persistence_path}")
130
+ end
131
+ end
101
132
 
102
- # database
103
- #end
104
- end
133
+ class << self
134
+ alias load_stream importtsv
135
+ end
105
136
 
106
- Persist.save_drivers[:HDB] = proc do |file, content|
107
- data = ScoutCabinet.open(file, true, "HDB")
108
- content.annotate(data)
109
- data.extend TSVAdapter
110
- data.merge!(content)
111
- data
112
- end
137
+ def importtsv(stream)
138
+ ScoutCabinet.load_stream(self, stream)
139
+ end
113
140
 
114
- Persist.load_drivers[:HDB] = proc do |file|
115
- data = ScoutCabinet.open(file, false, "HDB")
116
- data.extend TSVAdapter unless TSVAdapter === data
117
- data
141
+ alias load_stream importtsv
118
142
  end
@@ -0,0 +1,4 @@
1
+ require_relative 'engine/tokyocabinet'
2
+ require_relative 'engine/fix_width_table'
3
+ require_relative 'engine/packed_index'
4
+ require_relative 'engine/sharder'
@@ -1,6 +1,5 @@
1
1
  require 'scout/open/lock'
2
- require 'scout/meta_extension'
3
- require_relative 'serialize'
2
+ require 'scout/annotation'
4
3
 
5
4
  module TSVAdapter
6
5
  attr_accessor :persistence_path, :persistence_class, :closed, :writable, :serializer
@@ -12,81 +11,114 @@ module TSVAdapter
12
11
  end
13
12
  end
14
13
 
15
- EXTENSION_ATTR_HASH_KEY = "__extension_attr_hash__"
16
- EXTENSION_ATTR_HASH_SERIALIZER = Marshal
14
+ ANNOTATION_ATTR_HASH_KEY = "__annotation_hash__"
15
+ ANNOTATION_ATTR_HASH_SERIALIZER = Marshal
17
16
 
18
17
  def serializer=(serializer)
19
18
  @serializer = Symbol === serializer ? SERIALIZER_ALIAS[serializer] : serializer
20
19
  end
21
20
 
22
- def load_extension_attr_hash
23
- EXTENSION_ATTR_HASH_SERIALIZER.load(StringIO.new(self.orig_get(EXTENSION_ATTR_HASH_KEY)))
21
+ def load_annotation_hash
22
+ ANNOTATION_ATTR_HASH_SERIALIZER.load(StringIO.new(self.orig_get(ANNOTATION_ATTR_HASH_KEY)))
24
23
  end
25
24
 
26
- def save_extension_attr_hash
27
- self.orig_set(EXTENSION_ATTR_HASH_KEY, EXTENSION_ATTR_HASH_SERIALIZER.dump(self.extension_attr_hash))
25
+ def save_annotation_hash
26
+ self.orig_set(ANNOTATION_ATTR_HASH_KEY, ANNOTATION_ATTR_HASH_SERIALIZER.dump(self.annotation_hash))
28
27
  end
29
28
 
30
29
  def self.extended(base)
31
- return if base.respond_to?(:orig_set)
32
-
33
- class << base
34
- alias orig_set []=
35
- alias orig_get []
36
-
37
- def [](key)
38
- self.read_lock do
39
- load_value(super(key))
40
- end
30
+ if TSV === base
31
+ base.instance_variable_get(:@annotations).push(:serializer)
32
+ base.serializer = SERIALIZER_ALIAS[base.type] if base.serializer.nil?
33
+ base.save_annotation_hash
34
+ else
35
+ begin
36
+ TSV.setup(base, base.load_annotation_hash)
37
+ rescue
38
+ TSV.setup(base)
39
+ base.save_annotation_hash
41
40
  end
41
+ end
42
+ end
42
43
 
43
- def []=(key, value)
44
- self.write_lock do
45
- super(key, save_value(value))
46
- end
47
- end
44
+ def []=(...) super(...); end
45
+ def [](...) super(...); end
46
+ def keys(...) super(...); end
47
+ def each(...) super(...); end
48
+ def size(...) super(...); end
48
49
 
49
- def load_value(str)
50
- return nil if str.nil?
51
- serializer.load(str)
52
- end
50
+ alias orig_set []=
51
+ alias orig_get []
52
+ alias orig_keys keys
53
+ alias orig_each each
54
+ alias orig_size size
53
55
 
54
- def save_value(value)
55
- serializer.dump(value)
56
- end
56
+ def [](key, clean = false)
57
+ self.read_lock do
58
+ v = super(key)
59
+ return v if clean
60
+ v = load_value(v)
61
+ NamedArray.setup(v, @fields, key) unless @unnamed || ! (Array === v)
62
+ v
57
63
  end
64
+ end
58
65
 
59
- if base.include?(EXTENSION_ATTR_HASH_KEY)
60
- TSV.setup(base, base.load_extension_attr_hash)
61
- else
62
- base.instance_variable_get(:@extension_attrs).push :serializer
63
- base.serializer = SERIALIZER_ALIAS[base.type] if base.serializer.nil?
64
- base.save_extension_attr_hash
66
+ def []=(key, value, clean = false)
67
+ self.write_lock do
68
+ if clean
69
+ super(key, value)
70
+ else
71
+ super(key, save_value(value))
72
+ end
65
73
  end
66
74
  end
67
75
 
68
- def keys(*args)
76
+ def load_value(str)
77
+ return nil if str.nil?
78
+ return str if serializer.nil?
79
+ return load_value(str.first) if Array === str
80
+ serializer.load(str)
81
+ end
82
+
83
+ def save_value(value)
84
+ return nil if value.nil?
85
+ return value if serializer.nil?
86
+ serializer.dump(value)
87
+ end
88
+
89
+ def keys_annotation_hash_key(*args)
69
90
  k = self.read_lock do
70
- super(*args)
91
+ orig_keys(*args)
71
92
  end
72
93
 
73
- if k[0] == EXTENSION_ATTR_HASH_KEY
94
+ if k[0] == ANNOTATION_ATTR_HASH_KEY
74
95
  k.slice(1,k.length)
75
- elsif k[-1] == EXTENSION_ATTR_HASH_KEY
96
+ elsif k[-1] == ANNOTATION_ATTR_HASH_KEY
76
97
  k.slice(0,k.length-1)
77
98
  else
78
- k - [EXTENSION_ATTR_HASH_KEY]
99
+ k - [ANNOTATION_ATTR_HASH_KEY]
79
100
  end
80
101
  end
102
+ alias keys keys_annotation_hash_key
81
103
 
82
- def each(&block)
104
+ def each_annotation_hash_key(&block)
83
105
  self.read_lock do
84
- super do |k,v|
85
- next if k == EXTENSION_ATTR_HASH_KEY
106
+ orig_each do |k,v|
107
+ next if k == ANNOTATION_ATTR_HASH_KEY
86
108
  yield(k, load_value(v))
87
109
  end
88
110
  end
89
111
  end
112
+ alias each each_annotation_hash_key
113
+
114
+ def size_annotation_hash_key(*args)
115
+ self.read_lock do
116
+ orig_size(*args) - 1 # Discount the ANNOTATION_ATTR_HASH_KEY
117
+ end
118
+ end
119
+ alias size size_annotation_hash_key
120
+
121
+ alias length size
90
122
 
91
123
  def collect(&block)
92
124
  res = []
@@ -122,7 +154,10 @@ module TSVAdapter
122
154
 
123
155
  def write(*args)
124
156
  begin
125
- super(*args)
157
+ begin
158
+ super(*args)
159
+ rescue
160
+ end
126
161
  @writable = true
127
162
  rescue NoMethodError
128
163
  end
@@ -321,12 +356,6 @@ module TSVAdapter
321
356
  select(:key => keys)
322
357
  end
323
358
 
324
- def size(*args)
325
- self.read_lock do
326
- super(*args)
327
- end
328
- end
329
-
330
359
  def values_at(*keys)
331
360
  self.read_lock do
332
361
  keys.collect do |k|