rbbt-util 5.44.1 → 6.0.4

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.
Files changed (175) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/bin/rbbt +67 -90
  4. data/bin/rbbt_exec.rb +2 -2
  5. data/etc/app.d/base.rb +2 -2
  6. data/etc/app.d/semaphores.rb +3 -3
  7. data/lib/rbbt/annotations/annotated_array.rb +207 -207
  8. data/lib/rbbt/annotations/refactor.rb +27 -0
  9. data/lib/rbbt/annotations/util.rb +282 -282
  10. data/lib/rbbt/annotations.rb +343 -320
  11. data/lib/rbbt/association/database.rb +200 -225
  12. data/lib/rbbt/association/index.rb +294 -291
  13. data/lib/rbbt/association/item.rb +227 -227
  14. data/lib/rbbt/association/open.rb +35 -34
  15. data/lib/rbbt/association/util.rb +0 -169
  16. data/lib/rbbt/association.rb +2 -4
  17. data/lib/rbbt/entity/identifiers.rb +119 -118
  18. data/lib/rbbt/entity/refactor.rb +12 -0
  19. data/lib/rbbt/entity.rb +319 -315
  20. data/lib/rbbt/hpc/batch.rb +72 -53
  21. data/lib/rbbt/hpc/lsf.rb +2 -2
  22. data/lib/rbbt/hpc/orchestrate/batches.rb +2 -2
  23. data/lib/rbbt/hpc/orchestrate/chains.rb +25 -5
  24. data/lib/rbbt/hpc/orchestrate/rules.rb +2 -2
  25. data/lib/rbbt/hpc/orchestrate.rb +19 -13
  26. data/lib/rbbt/hpc/slurm.rb +18 -18
  27. data/lib/rbbt/knowledge_base/entity.rb +13 -5
  28. data/lib/rbbt/knowledge_base/query.rb +2 -2
  29. data/lib/rbbt/knowledge_base/registry.rb +32 -31
  30. data/lib/rbbt/knowledge_base/traverse.rb +1 -1
  31. data/lib/rbbt/knowledge_base.rb +1 -1
  32. data/lib/rbbt/monitor.rb +36 -25
  33. data/lib/rbbt/persist/refactor.rb +166 -0
  34. data/lib/rbbt/persist/tsv/tokyocabinet.rb +105 -105
  35. data/lib/rbbt/persist/tsv.rb +187 -185
  36. data/lib/rbbt/persist.rb +556 -551
  37. data/lib/rbbt/refactor.rb +20 -0
  38. data/lib/rbbt/resource/path/refactor.rb +178 -0
  39. data/lib/rbbt/resource/path.rb +317 -497
  40. data/lib/rbbt/resource/util.rb +0 -48
  41. data/lib/rbbt/resource.rb +3 -390
  42. data/lib/rbbt/tsv/accessor.rb +2 -838
  43. data/lib/rbbt/tsv/attach.rb +303 -299
  44. data/lib/rbbt/tsv/change_id.rb +244 -245
  45. data/lib/rbbt/tsv/csv.rb +87 -85
  46. data/lib/rbbt/tsv/dumper.rb +2 -100
  47. data/lib/rbbt/tsv/excel.rb +26 -24
  48. data/lib/rbbt/tsv/field_index.rb +4 -1
  49. data/lib/rbbt/tsv/filter.rb +3 -2
  50. data/lib/rbbt/tsv/index.rb +2 -284
  51. data/lib/rbbt/tsv/manipulate.rb +750 -747
  52. data/lib/rbbt/tsv/marshal.rb +3 -3
  53. data/lib/rbbt/tsv/matrix.rb +2 -2
  54. data/lib/rbbt/tsv/parallel/through.rb +2 -1
  55. data/lib/rbbt/tsv/parallel/traverse.rb +783 -781
  56. data/lib/rbbt/tsv/parser.rb +678 -678
  57. data/lib/rbbt/tsv/refactor.rb +195 -0
  58. data/lib/rbbt/tsv/stream.rb +253 -251
  59. data/lib/rbbt/tsv/util.rb +420 -420
  60. data/lib/rbbt/tsv.rb +210 -208
  61. data/lib/rbbt/util/R/eval.rb +4 -4
  62. data/lib/rbbt/util/R/plot.rb +62 -166
  63. data/lib/rbbt/util/R.rb +21 -18
  64. data/lib/rbbt/util/cmd.rb +2 -318
  65. data/lib/rbbt/util/color.rb +269 -269
  66. data/lib/rbbt/util/colorize.rb +89 -89
  67. data/lib/rbbt/util/concurrency/processes/refactor.rb +22 -0
  68. data/lib/rbbt/util/concurrency/processes/worker.rb +2 -2
  69. data/lib/rbbt/util/concurrency/processes.rb +389 -386
  70. data/lib/rbbt/util/config.rb +169 -167
  71. data/lib/rbbt/util/filecache.rb +1 -1
  72. data/lib/rbbt/util/iruby.rb +20 -0
  73. data/lib/rbbt/util/log/progress/report.rb +241 -241
  74. data/lib/rbbt/util/log/progress/util.rb +99 -99
  75. data/lib/rbbt/util/log/progress.rb +102 -102
  76. data/lib/rbbt/util/log/refactor.rb +49 -0
  77. data/lib/rbbt/util/log.rb +486 -532
  78. data/lib/rbbt/util/migrate.rb +2 -2
  79. data/lib/rbbt/util/misc/concurrent_stream.rb +248 -246
  80. data/lib/rbbt/util/misc/development.rb +12 -11
  81. data/lib/rbbt/util/misc/exceptions.rb +117 -112
  82. data/lib/rbbt/util/misc/format.rb +2 -230
  83. data/lib/rbbt/util/misc/indiferent_hash.rb +2 -107
  84. data/lib/rbbt/util/misc/inspect.rb +2 -476
  85. data/lib/rbbt/util/misc/lock.rb +109 -106
  86. data/lib/rbbt/util/misc/omics.rb +9 -1
  87. data/lib/rbbt/util/misc/pipes.rb +765 -793
  88. data/lib/rbbt/util/misc/refactor.rb +20 -0
  89. data/lib/rbbt/util/misc/ssw.rb +27 -17
  90. data/lib/rbbt/util/misc/system.rb +92 -105
  91. data/lib/rbbt/util/misc.rb +39 -20
  92. data/lib/rbbt/util/named_array/refactor.rb +4 -0
  93. data/lib/rbbt/util/named_array.rb +3 -220
  94. data/lib/rbbt/util/open/refactor.rb +7 -0
  95. data/lib/rbbt/util/open.rb +3 -857
  96. data/lib/rbbt/util/procpath.rb +6 -6
  97. data/lib/rbbt/util/python/paths.rb +27 -0
  98. data/lib/rbbt/util/python/run.rb +115 -0
  99. data/lib/rbbt/util/python/script.rb +110 -0
  100. data/lib/rbbt/util/python/util.rb +3 -3
  101. data/lib/rbbt/util/python.rb +22 -81
  102. data/lib/rbbt/util/semaphore.rb +152 -148
  103. data/lib/rbbt/util/simpleopt.rb +9 -8
  104. data/lib/rbbt/util/ssh/refactor.rb +19 -0
  105. data/lib/rbbt/util/ssh.rb +122 -118
  106. data/lib/rbbt/util/tar.rb +117 -115
  107. data/lib/rbbt/util/tmpfile.rb +69 -67
  108. data/lib/rbbt/util/version.rb +2 -0
  109. data/lib/rbbt/workflow/refactor/entity.rb +11 -0
  110. data/lib/rbbt/workflow/refactor/export.rb +66 -0
  111. data/lib/rbbt/workflow/refactor/inputs.rb +24 -0
  112. data/lib/rbbt/workflow/refactor/recursive.rb +64 -0
  113. data/lib/rbbt/workflow/refactor/task_info.rb +66 -0
  114. data/lib/rbbt/workflow/refactor.rb +150 -0
  115. data/lib/rbbt/workflow/remote_workflow/driver/rest.rb +1 -2
  116. data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +55 -32
  117. data/lib/rbbt/workflow/remote_workflow/remote_step/rest.rb +3 -1
  118. data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +14 -5
  119. data/lib/rbbt/workflow/remote_workflow/remote_step.rb +19 -7
  120. data/lib/rbbt/workflow/remote_workflow.rb +6 -1
  121. data/lib/rbbt/workflow/step/run.rb +766 -766
  122. data/lib/rbbt/workflow/step/save_load_inputs.rb +254 -254
  123. data/lib/rbbt/workflow/step.rb +2 -362
  124. data/lib/rbbt/workflow/task.rb +118 -118
  125. data/lib/rbbt/workflow/usage.rb +289 -287
  126. data/lib/rbbt/workflow/util/archive.rb +6 -5
  127. data/lib/rbbt/workflow/util/data.rb +1 -1
  128. data/lib/rbbt/workflow/util/orchestrator.rb +249 -246
  129. data/lib/rbbt/workflow/util/trace.rb +79 -44
  130. data/lib/rbbt/workflow.rb +4 -882
  131. data/lib/rbbt-util.rb +21 -13
  132. data/lib/rbbt.rb +16 -3
  133. data/python/rbbt/__init__.py +96 -4
  134. data/python/rbbt/workflow/remote.py +104 -0
  135. data/python/rbbt/workflow.py +64 -0
  136. data/python/test.py +10 -0
  137. data/share/Rlib/plot.R +37 -37
  138. data/share/Rlib/svg.R +22 -5
  139. data/share/install/software/lib/install_helpers +1 -1
  140. data/share/rbbt_commands/hpc/list +2 -3
  141. data/share/rbbt_commands/hpc/orchestrate +4 -4
  142. data/share/rbbt_commands/hpc/tail +2 -0
  143. data/share/rbbt_commands/hpc/task +10 -7
  144. data/share/rbbt_commands/lsf/list +2 -3
  145. data/share/rbbt_commands/lsf/orchestrate +4 -4
  146. data/share/rbbt_commands/lsf/tail +2 -0
  147. data/share/rbbt_commands/lsf/task +10 -7
  148. data/share/rbbt_commands/migrate +1 -1
  149. data/share/rbbt_commands/pbs/list +2 -3
  150. data/share/rbbt_commands/pbs/orchestrate +4 -4
  151. data/share/rbbt_commands/pbs/tail +2 -0
  152. data/share/rbbt_commands/pbs/task +10 -7
  153. data/share/rbbt_commands/resource/produce +8 -1
  154. data/share/rbbt_commands/slurm/list +2 -3
  155. data/share/rbbt_commands/slurm/orchestrate +4 -4
  156. data/share/rbbt_commands/slurm/tail +2 -0
  157. data/share/rbbt_commands/slurm/task +10 -7
  158. data/share/rbbt_commands/system/clean +5 -5
  159. data/share/rbbt_commands/system/status +5 -5
  160. data/share/rbbt_commands/tsv/get +2 -3
  161. data/share/rbbt_commands/tsv/info +10 -13
  162. data/share/rbbt_commands/tsv/keys +18 -14
  163. data/share/rbbt_commands/tsv/slice +2 -2
  164. data/share/rbbt_commands/tsv/transpose +6 -2
  165. data/share/rbbt_commands/workflow/info +20 -24
  166. data/share/rbbt_commands/workflow/list +1 -1
  167. data/share/rbbt_commands/workflow/prov +20 -13
  168. data/share/rbbt_commands/workflow/retry +43 -0
  169. data/share/rbbt_commands/workflow/server +12 -2
  170. data/share/rbbt_commands/workflow/task +80 -73
  171. data/share/rbbt_commands/workflow/write_info +26 -9
  172. data/share/software/opt/ssw/ssw.c +861 -0
  173. data/share/software/opt/ssw/ssw.h +130 -0
  174. data/share/workflow_config.ru +3 -3
  175. metadata +45 -6
@@ -1,291 +1,294 @@
1
- require 'rbbt/tsv'
2
- require 'rbbt/association/open'
3
- require 'rbbt/association/item'
4
-
5
- module Association
6
- def self.index(file, options = nil, persist_options = nil)
7
- options = options.nil? ? {} : options.dup
8
- persist_options = persist_options.nil? ? Misc.pull_keys(options, :persist) : persist_options.dup
9
- persist_options[:serializer] ||= options[:serializer] if options.include?(:serializer)
10
-
11
- persist_options = Misc.add_defaults persist_options.dup, :persist => true, :dir => Rbbt.var.associations
12
- persist = persist_options[:persist]
13
-
14
- file = version_file(file, options[:namespace]) if options[:namespace] and String === file
15
- Persist.persist_tsv(file, nil, options, persist_options.merge(:engine => "BDB", :prefix => "Association Index")) do |data|
16
- options = Misc.add_defaults options.dup, :monitor => "Building index for #{Misc.fingerprint file}"
17
- recycle = options[:recycle]
18
- undirected = options[:undirected]
19
-
20
- serializer = persist_options[:serializer] || :list
21
-
22
- persist_options[:file] = persist_options[:file] + '.database' if persist_options[:file]
23
-
24
- database = open(file, options, persist_options.dup.merge(:engine => "HDB"))
25
-
26
- source_field = database.key_field
27
-
28
- fields = database.fields
29
- target_field = fields.first.split(":").last
30
-
31
- undirected = true if undirected.nil? and source_field == target_field
32
-
33
- key_field = [source_field, target_field, undirected ? "undirected" : nil].compact * "~"
34
-
35
- TSV.setup(data, :key_field => key_field, :fields => fields[1..-1], :type => :list, :serializer => serializer, :namespace => database.namespace)
36
-
37
- data.key_field = key_field
38
- data.fields = fields[1..-1]
39
- data.type = :list
40
- data.serializer ||= serializer
41
- data.filename ||= file if String === file
42
-
43
- database.with_unnamed do
44
- database.with_monitor(options[:monitor]) do
45
- database.through do |source, values|
46
- case database.type
47
- when :single
48
- values = [[values]]
49
- when :list
50
- values = values.collect{|v| [v] }
51
- when :flat
52
- values = [values]
53
- end
54
- next if values.empty?
55
- next if source.nil? or source.empty?
56
- next if values.empty?
57
-
58
- #targets, *rest = Misc.zip_fields(Misc.zip_fields(values).uniq)
59
-
60
- next if values.first.empty?
61
- values = Misc.zip_fields(Misc.zip_fields(values).uniq)
62
- targets, *rest = values
63
-
64
- size = targets ? targets.length : 0
65
-
66
- rest.each_with_index do |list,i|
67
- list.replace [list.first] * size if list.length == 1
68
- end if recycle and size > 1
69
-
70
- rest = Misc.zip_fields rest
71
-
72
- annotations = (Array === rest.first and rest.first.length > 1) ?
73
- targets.zip(rest) :
74
- targets.zip(rest * targets.length)
75
-
76
- source = source.gsub('~','-..-')
77
- annotations.each do |target, info|
78
- next if target.nil? or target.empty?
79
- target = target.gsub('~','-..-')
80
- key = [source, target] * "~"
81
-
82
- if data[key].nil? or info.nil?
83
- data[key] = info
84
- else
85
- old_info = data[key]
86
- info = old_info.zip(info).collect{|p| p * ";;" }
87
- data[key] = info
88
- end
89
- end
90
- end
91
-
92
- if undirected
93
- new_data = {}
94
-
95
- data.through do |key,values|
96
- reverse_key = key.split("~").reverse * "~"
97
- new_data[reverse_key] = values
98
- end
99
-
100
- new_data.each do |key,values|
101
- data[key] = values
102
- end
103
- end
104
-
105
- end
106
- end
107
-
108
- data
109
- end.tap do |data|
110
- data.read if not Hash === data and data.respond_to? :read
111
- Association::Index.setup data
112
- data.entity_options = options[:entity_options] if options[:entity_options]
113
- data
114
- end
115
- end
116
-
117
- module Index
118
-
119
- attr_accessor :source_field, :target_field, :undirected
120
- def parse_key_field
121
- @source_field, @target_field, @undirected = key_field.split("~")
122
- end
123
-
124
- def self.setup(repo)
125
- repo.extend Association::Index
126
- repo.parse_key_field
127
- repo.unnamed = true
128
- repo
129
- end
130
-
131
- def reverse
132
- @reverse ||= begin
133
- if self.respond_to? :persistence_path
134
- persistence_path = self.persistence_path
135
- persistence_path = persistence_path.find if Path === persistence_path
136
- reverse_filename = persistence_path + '.reverse'
137
- else
138
- raise "Can only reverse a TokyoCabinet::BDB dataset at the time"
139
- end
140
-
141
- if File.exist?(reverse_filename)
142
- new = Persist.open_tokyocabinet(reverse_filename, false, serializer, TokyoCabinet::BDB)
143
- raise "Index has no info: #{reverse_filename}" if new.key_field.nil?
144
- Association::Index.setup new
145
- new
146
- else
147
- FileUtils.mkdir_p File.dirname(reverse_filename) unless File.exist?(File.dirname(reverse_filename))
148
-
149
- new = Persist.open_tokyocabinet(reverse_filename, true, serializer, TokyoCabinet::BDB)
150
-
151
- self.with_unnamed do
152
- self.with_monitor :desc => "Reversing #{ persistence_path }" do
153
- self.through do |key, value|
154
- new_key = key.split("~").reverse.join("~")
155
- new[new_key] = value
156
- end
157
- end
158
- end
159
- annotate(new)
160
- new.key_field = key_field.split("~").values_at(1,0,2).compact * "~"
161
- new.read_and_close do
162
- Association::Index.setup new
163
- end
164
- new.read
165
- end
166
-
167
- new.unnamed = true
168
-
169
- new.undirected = undirected
170
-
171
- new
172
- rescue Exception
173
- Log.error "Deleting after error reversing database: #{ reverse_filename }"
174
- FileUtils.rm reverse_filename if File.exist? reverse_filename
175
- raise $!
176
- end
177
- end
178
-
179
- def match(entity)
180
- return entity.inject([]){|acc,e| acc.concat match(e); acc } if Array === entity
181
- return [] if entity.nil?
182
- prefix(entity + "~")
183
- end
184
-
185
- def matches(entities)
186
- entities.inject(nil) do |acc,e|
187
- m = match(e);
188
- if acc.nil? or acc.empty?
189
- acc = m
190
- else
191
- acc.concat m
192
- end
193
- acc
194
- end
195
- end
196
-
197
- def filter(value_field = nil, target_value = nil, &block)
198
- if block_given?
199
- matches = []
200
- if value_field
201
- through :key, value_field do |key,values|
202
- pass = block.call values
203
- matches << key if pass
204
- end
205
- else
206
- through do |key,values|
207
- pass = block.call [key, values]
208
- matches << key if pass
209
- end
210
- end
211
- matches
212
-
213
- else
214
- matches = []
215
- if target_value
216
- target_value = [target_value] unless Array === target_value
217
- through :key, value_field do |key,values|
218
- pass = (values & target_value).any?
219
- matches << key if pass
220
- end
221
- else
222
- through :key, value_field do |key,values|
223
- pass = false
224
- values.each do |value|
225
- pass = true unless value.nil? or value.empty? or value.downcase == 'false'
226
- end
227
- matches << key if pass
228
- end
229
- end
230
- matches
231
- end
232
- end
233
-
234
- def to_matrix(value_field = nil, &block)
235
- value_field = fields.first if value_field.nil? and fields.length == 1
236
- value_pos = identify_field value_field if value_field and String === value_field
237
- key_field = source_field
238
-
239
- tsv = if value_pos
240
- AssociationItem.incidence self.keys, key_field do |key|
241
- if block_given?
242
- yield self[key][value_pos]
243
- else
244
- self[key][value_pos]
245
- end
246
- end
247
- elsif block_given?
248
- AssociationItem.incidence self.keys, key_field, &block
249
- else
250
- AssociationItem.incidence self.keys, key_field
251
- end
252
- end
253
-
254
- #{{{ Subset
255
-
256
- def subset(source, target)
257
- return [] if source.nil? or target.nil? or source.empty? or target.empty?
258
-
259
- if source == :all or source == "all"
260
- if target == :all or target == "all"
261
- return keys
262
- else
263
- matches = reverse.subset(target, source)
264
- return matches.collect{|m| r = m.partition "~"; r.reverse*"" }
265
- end
266
- end
267
-
268
- matches = source.uniq.inject([]){|acc,e|
269
- if block_given?
270
- acc.concat(match(e))
271
- else
272
- acc.concat(match(e))
273
- end
274
- }
275
-
276
- return matches if target == :all or target == "all"
277
-
278
- target_matches = {}
279
-
280
- matches.each{|code|
281
- s,sep,t = code.partition "~"
282
- next if undirected and t > s and source.include? t
283
- target_matches[t] ||= []
284
- target_matches[t] << code
285
- }
286
-
287
- target_matches.values_at(*target.uniq).flatten.compact
288
- end
289
-
290
- end
291
- end
1
+ require_relative '../refactor'
2
+ Rbbt.require_instead 'scout/association'
3
+ #require 'rbbt/tsv'
4
+ #require 'rbbt/association/open'
5
+ #require 'rbbt/association/item'
6
+ #require 'scout/association'
7
+ #require 'rbbt/tsv'
8
+ #require_relative 'item'
9
+ #
10
+ #module Association
11
+ # def self.index(file, options = nil, persist_options = nil)
12
+ # options = options.nil? ? {} : options.dup
13
+ # persist_options = persist_options.nil? ? IndiferentHash.pull_keys(options, :persist) : persist_options.dup
14
+ # persist_options[:serializer] ||= options[:serializer] if options.include?(:serializer)
15
+ #
16
+ # persist_options = IndiferentHash.add_defaults persist_options.dup, :persist => true, :dir => Rbbt.var.associations
17
+ # persist = persist_options[:persist]
18
+ #
19
+ # file = version_file(file, options[:namespace]) if options[:namespace] and String === file
20
+ # Persist.persist_tsv(file, nil, options, persist_options.merge(:engine => "BDB", :prefix => "Association Index")) do |data|
21
+ # options = IndiferentHash.add_defaults options.dup, :monitor => "Building index for #{Log.fingerprint file}"
22
+ # recycle, undirected = IndiferentHash.process_options options, :recycle, :undirected
23
+ #
24
+ # serializer = persist_options[:serializer] || :list
25
+ #
26
+ # persist_options[:file] = persist_options[:file] + '.database' if persist_options[:file]
27
+ #
28
+ # database = database(file, **options)
29
+ #
30
+ # source_field = database.key_field
31
+ #
32
+ # fields = database.fields
33
+ # target_field = fields.first.split(":").last
34
+ #
35
+ # undirected = true if undirected.nil? and source_field == target_field
36
+ #
37
+ # key_field = [source_field, target_field, undirected ? "undirected" : nil].compact * "~"
38
+ #
39
+ # TSV.setup(data, :key_field => key_field, :fields => fields[1..-1], :type => :list, :namespace => database.namespace)
40
+ #
41
+ # data.key_field = key_field
42
+ # data.fields = fields[1..-1]
43
+ # data.type = :list
44
+ # data.serializer = serializer if data.respond_to?(:serializer)
45
+ # data.filename ||= file if String === file
46
+ #
47
+ # database.with_unnamed do
48
+ # database.traverse do |source, values|
49
+ # case database.type
50
+ # when :single
51
+ # values = [[values]]
52
+ # when :list
53
+ # values = values.collect{|v| [v] }
54
+ # when :flat
55
+ # values = [values]
56
+ # end
57
+ # next if values.empty?
58
+ # next if source.nil? or source.empty?
59
+ # next if values.empty?
60
+ #
61
+ # #targets, *rest = Misc.zip_fields(Misc.zip_fields(values).uniq)
62
+ #
63
+ # next if values.first.empty?
64
+ # values = NamedArray.zip_fields(NamedArray.zip_fields(values).uniq)
65
+ # targets, *rest = values
66
+ #
67
+ # size = targets ? targets.length : 0
68
+ #
69
+ # rest.each_with_index do |list,i|
70
+ # list.replace [list.first] * size if list.length == 1
71
+ # end if recycle and size > 1
72
+ #
73
+ # rest = NamedArray.zip_fields rest
74
+ #
75
+ # annotations = (Array === rest.first and rest.first.length > 1) ?
76
+ # targets.zip(rest) :
77
+ # targets.zip(rest * targets.length)
78
+ #
79
+ # source = source.gsub('~','-..-')
80
+ # annotations.each do |target, info|
81
+ # next if target.nil? or target.empty?
82
+ # info ||= [] if info.nil?
83
+ # target = target.gsub('~','-..-')
84
+ # key = [source, target] * "~"
85
+ #
86
+ # if data[key].nil? or info.nil?
87
+ # data[key] = info
88
+ # else
89
+ # old_info = data[key]
90
+ # info = old_info.zip(info).collect{|p| p * ";;" }
91
+ # data[key] = info
92
+ # end
93
+ # end
94
+ # end
95
+ #
96
+ # if undirected
97
+ # new_data = {}
98
+ #
99
+ # data.through do |key,values|
100
+ # reverse_key = key.split("~").reverse * "~"
101
+ # new_data[reverse_key] = values
102
+ # end
103
+ #
104
+ # new_data.each do |key,values|
105
+ # data[key] = values
106
+ # end
107
+ # end
108
+ #
109
+ # end
110
+ #
111
+ # data
112
+ # end.tap do |data|
113
+ # data.read if not Hash === data and data.respond_to? :read
114
+ # Association::Index.setup data
115
+ # data.entity_options = options[:entity_options] if options[:entity_options]
116
+ # data
117
+ # end
118
+ # end
119
+ #
120
+ # module Index
121
+ #
122
+ # attr_accessor :source_field, :target_field, :undirected
123
+ # def parse_key_field
124
+ # @source_field, @target_field, @undirected = key_field.split("~")
125
+ # end
126
+ #
127
+ # def self.setup(repo)
128
+ # repo.extend Association::Index
129
+ # repo.parse_key_field
130
+ # repo.unnamed = true
131
+ # repo
132
+ # end
133
+ #
134
+ # def reverse
135
+ # @reverse ||= begin
136
+ # if self.respond_to? :persistence_path
137
+ # persistence_path = self.persistence_path
138
+ # persistence_path = persistence_path.find if Path === persistence_path
139
+ # reverse_filename = persistence_path + '.reverse'
140
+ # else
141
+ # raise "Can only reverse a TokyoCabinet::BDB dataset at the time"
142
+ # end
143
+ #
144
+ # if File.exist?(reverse_filename)
145
+ # new = Persist.open_tokyocabinet(reverse_filename, false, serializer, TokyoCabinet::BDB)
146
+ # raise "Index has no info: #{reverse_filename}" if new.key_field.nil?
147
+ # Association::Index.setup new
148
+ # new
149
+ # else
150
+ # FileUtils.mkdir_p File.dirname(reverse_filename) unless File.exist?(File.dirname(reverse_filename))
151
+ #
152
+ # new = Persist.open_tokyocabinet(reverse_filename, true, serializer, TokyoCabinet::BDB)
153
+ #
154
+ # self.with_unnamed do
155
+ # self.with_monitor :desc => "Reversing #{ persistence_path }" do
156
+ # self.through do |key, value|
157
+ # new_key = key.split("~").reverse.join("~")
158
+ # new[new_key] = value
159
+ # end
160
+ # end
161
+ # end
162
+ # annotate(new)
163
+ # new.key_field = key_field.split("~").values_at(1,0,2).compact * "~"
164
+ # new.read_and_close do
165
+ # Association::Index.setup new
166
+ # end
167
+ # new.read
168
+ # end
169
+ #
170
+ # new.unnamed = true
171
+ #
172
+ # new.undirected = undirected
173
+ #
174
+ # new
175
+ # rescue Exception
176
+ # Log.error "Deleting after error reversing database: #{ reverse_filename }"
177
+ # FileUtils.rm reverse_filename if File.exist? reverse_filename
178
+ # raise $!
179
+ # end
180
+ # end
181
+ #
182
+ # def match(entity)
183
+ # return entity.inject([]){|acc,e| acc.concat match(e); acc } if Array === entity
184
+ # return [] if entity.nil?
185
+ # prefix(entity + "~")
186
+ # end
187
+ #
188
+ # def matches(entities)
189
+ # entities.inject(nil) do |acc,e|
190
+ # m = match(e);
191
+ # if acc.nil? or acc.empty?
192
+ # acc = m
193
+ # else
194
+ # acc.concat m
195
+ # end
196
+ # acc
197
+ # end
198
+ # end
199
+ #
200
+ # def filter(value_field = nil, target_value = nil, &block)
201
+ # if block_given?
202
+ # matches = []
203
+ # if value_field
204
+ # through :key, value_field do |key,values|
205
+ # pass = block.call values
206
+ # matches << key if pass
207
+ # end
208
+ # else
209
+ # through do |key,values|
210
+ # pass = block.call [key, values]
211
+ # matches << key if pass
212
+ # end
213
+ # end
214
+ # matches
215
+ #
216
+ # else
217
+ # matches = []
218
+ # if target_value
219
+ # target_value = [target_value] unless Array === target_value
220
+ # through :key, value_field do |key,values|
221
+ # pass = (values & target_value).any?
222
+ # matches << key if pass
223
+ # end
224
+ # else
225
+ # through :key, value_field do |key,values|
226
+ # pass = false
227
+ # values.each do |value|
228
+ # pass = true unless value.nil? or value.empty? or value.downcase == 'false'
229
+ # end
230
+ # matches << key if pass
231
+ # end
232
+ # end
233
+ # matches
234
+ # end
235
+ # end
236
+ #
237
+ # def to_matrix(value_field = nil, &block)
238
+ # value_field = fields.first if value_field.nil? and fields.length == 1
239
+ # value_pos = identify_field value_field if value_field and String === value_field
240
+ # key_field = source_field
241
+ #
242
+ # tsv = if value_pos
243
+ # AssociationItem.incidence self.keys, key_field do |key|
244
+ # if block_given?
245
+ # yield self[key][value_pos]
246
+ # else
247
+ # self[key][value_pos]
248
+ # end
249
+ # end
250
+ # elsif block_given?
251
+ # AssociationItem.incidence self.keys, key_field, &block
252
+ # else
253
+ # AssociationItem.incidence self.keys, key_field
254
+ # end
255
+ # end
256
+ #
257
+ # #{{{ Subset
258
+ #
259
+ # def subset(source, target)
260
+ # return [] if source.nil? or target.nil? or source.empty? or target.empty?
261
+ #
262
+ # if source == :all or source == "all"
263
+ # if target == :all or target == "all"
264
+ # return keys
265
+ # else
266
+ # matches = reverse.subset(target, source)
267
+ # return matches.collect{|m| r = m.partition "~"; r.reverse*"" }
268
+ # end
269
+ # end
270
+ #
271
+ # matches = source.uniq.inject([]){|acc,e|
272
+ # if block_given?
273
+ # acc.concat(match(e))
274
+ # else
275
+ # acc.concat(match(e))
276
+ # end
277
+ # }
278
+ #
279
+ # return matches if target == :all or target == "all"
280
+ #
281
+ # target_matches = {}
282
+ #
283
+ # matches.each{|code|
284
+ # s,sep,t = code.partition "~"
285
+ # next if undirected and t > s and source.include? t
286
+ # target_matches[t] ||= []
287
+ # target_matches[t] << code
288
+ # }
289
+ #
290
+ # target_matches.values_at(*target.uniq).flatten.compact
291
+ # end
292
+ #
293
+ # end
294
+ #end