rbbt-util 5.44.1 → 6.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rbbt +67 -90
  3. data/etc/app.d/base.rb +2 -2
  4. data/etc/app.d/semaphores.rb +3 -3
  5. data/lib/rbbt/annotations/annotated_array.rb +207 -207
  6. data/lib/rbbt/annotations/refactor.rb +27 -0
  7. data/lib/rbbt/annotations/util.rb +282 -282
  8. data/lib/rbbt/annotations.rb +343 -320
  9. data/lib/rbbt/association/database.rb +200 -225
  10. data/lib/rbbt/association/index.rb +294 -291
  11. data/lib/rbbt/association/item.rb +227 -227
  12. data/lib/rbbt/association/open.rb +35 -34
  13. data/lib/rbbt/association/util.rb +0 -169
  14. data/lib/rbbt/association.rb +2 -4
  15. data/lib/rbbt/entity/identifiers.rb +119 -118
  16. data/lib/rbbt/entity/refactor.rb +12 -0
  17. data/lib/rbbt/entity.rb +319 -315
  18. data/lib/rbbt/hpc/batch.rb +72 -53
  19. data/lib/rbbt/hpc/lsf.rb +2 -2
  20. data/lib/rbbt/hpc/orchestrate/batches.rb +2 -2
  21. data/lib/rbbt/hpc/orchestrate/chains.rb +25 -5
  22. data/lib/rbbt/hpc/orchestrate/rules.rb +2 -2
  23. data/lib/rbbt/hpc/orchestrate.rb +19 -13
  24. data/lib/rbbt/hpc/slurm.rb +18 -18
  25. data/lib/rbbt/knowledge_base/entity.rb +13 -5
  26. data/lib/rbbt/knowledge_base/query.rb +2 -2
  27. data/lib/rbbt/knowledge_base/registry.rb +32 -31
  28. data/lib/rbbt/knowledge_base/traverse.rb +1 -1
  29. data/lib/rbbt/knowledge_base.rb +1 -1
  30. data/lib/rbbt/monitor.rb +36 -25
  31. data/lib/rbbt/persist/refactor.rb +166 -0
  32. data/lib/rbbt/persist/tsv/tokyocabinet.rb +105 -105
  33. data/lib/rbbt/persist/tsv.rb +187 -185
  34. data/lib/rbbt/persist.rb +556 -551
  35. data/lib/rbbt/refactor.rb +20 -0
  36. data/lib/rbbt/resource/path/refactor.rb +178 -0
  37. data/lib/rbbt/resource/path.rb +317 -497
  38. data/lib/rbbt/resource/util.rb +0 -48
  39. data/lib/rbbt/resource.rb +3 -390
  40. data/lib/rbbt/tsv/accessor.rb +2 -838
  41. data/lib/rbbt/tsv/attach.rb +303 -299
  42. data/lib/rbbt/tsv/change_id.rb +244 -245
  43. data/lib/rbbt/tsv/csv.rb +87 -85
  44. data/lib/rbbt/tsv/dumper.rb +2 -100
  45. data/lib/rbbt/tsv/excel.rb +26 -24
  46. data/lib/rbbt/tsv/field_index.rb +4 -1
  47. data/lib/rbbt/tsv/filter.rb +3 -2
  48. data/lib/rbbt/tsv/index.rb +2 -284
  49. data/lib/rbbt/tsv/manipulate.rb +750 -747
  50. data/lib/rbbt/tsv/marshal.rb +3 -3
  51. data/lib/rbbt/tsv/matrix.rb +2 -2
  52. data/lib/rbbt/tsv/parallel/through.rb +2 -1
  53. data/lib/rbbt/tsv/parallel/traverse.rb +783 -781
  54. data/lib/rbbt/tsv/parser.rb +678 -678
  55. data/lib/rbbt/tsv/refactor.rb +195 -0
  56. data/lib/rbbt/tsv/stream.rb +253 -251
  57. data/lib/rbbt/tsv/util.rb +420 -420
  58. data/lib/rbbt/tsv.rb +210 -208
  59. data/lib/rbbt/util/R/eval.rb +4 -4
  60. data/lib/rbbt/util/R/plot.rb +62 -166
  61. data/lib/rbbt/util/R.rb +21 -18
  62. data/lib/rbbt/util/cmd.rb +2 -318
  63. data/lib/rbbt/util/color.rb +269 -269
  64. data/lib/rbbt/util/colorize.rb +89 -89
  65. data/lib/rbbt/util/concurrency/processes/refactor.rb +22 -0
  66. data/lib/rbbt/util/concurrency/processes/worker.rb +2 -2
  67. data/lib/rbbt/util/concurrency/processes.rb +389 -386
  68. data/lib/rbbt/util/config.rb +169 -167
  69. data/lib/rbbt/util/iruby.rb +20 -0
  70. data/lib/rbbt/util/log/progress/report.rb +241 -241
  71. data/lib/rbbt/util/log/progress/util.rb +99 -99
  72. data/lib/rbbt/util/log/progress.rb +102 -102
  73. data/lib/rbbt/util/log/refactor.rb +49 -0
  74. data/lib/rbbt/util/log.rb +486 -532
  75. data/lib/rbbt/util/migrate.rb +1 -1
  76. data/lib/rbbt/util/misc/concurrent_stream.rb +248 -246
  77. data/lib/rbbt/util/misc/development.rb +12 -11
  78. data/lib/rbbt/util/misc/exceptions.rb +117 -112
  79. data/lib/rbbt/util/misc/format.rb +2 -230
  80. data/lib/rbbt/util/misc/indiferent_hash.rb +2 -107
  81. data/lib/rbbt/util/misc/inspect.rb +2 -476
  82. data/lib/rbbt/util/misc/lock.rb +109 -106
  83. data/lib/rbbt/util/misc/omics.rb +9 -1
  84. data/lib/rbbt/util/misc/pipes.rb +765 -793
  85. data/lib/rbbt/util/misc/refactor.rb +20 -0
  86. data/lib/rbbt/util/misc/ssw.rb +27 -17
  87. data/lib/rbbt/util/misc/system.rb +0 -15
  88. data/lib/rbbt/util/misc.rb +39 -20
  89. data/lib/rbbt/util/named_array/refactor.rb +4 -0
  90. data/lib/rbbt/util/named_array.rb +3 -220
  91. data/lib/rbbt/util/open/refactor.rb +7 -0
  92. data/lib/rbbt/util/open.rb +3 -857
  93. data/lib/rbbt/util/procpath.rb +6 -6
  94. data/lib/rbbt/util/python/paths.rb +27 -0
  95. data/lib/rbbt/util/python/run.rb +115 -0
  96. data/lib/rbbt/util/python/script.rb +110 -0
  97. data/lib/rbbt/util/python/util.rb +3 -3
  98. data/lib/rbbt/util/python.rb +22 -81
  99. data/lib/rbbt/util/semaphore.rb +152 -148
  100. data/lib/rbbt/util/simpleopt.rb +9 -8
  101. data/lib/rbbt/util/ssh/refactor.rb +19 -0
  102. data/lib/rbbt/util/ssh.rb +122 -118
  103. data/lib/rbbt/util/tar.rb +117 -115
  104. data/lib/rbbt/util/tmpfile.rb +69 -67
  105. data/lib/rbbt/util/version.rb +2 -0
  106. data/lib/rbbt/workflow/refactor/entity.rb +11 -0
  107. data/lib/rbbt/workflow/refactor/export.rb +66 -0
  108. data/lib/rbbt/workflow/refactor/inputs.rb +24 -0
  109. data/lib/rbbt/workflow/refactor/recursive.rb +64 -0
  110. data/lib/rbbt/workflow/refactor/task_info.rb +65 -0
  111. data/lib/rbbt/workflow/refactor.rb +153 -0
  112. data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +55 -32
  113. data/lib/rbbt/workflow/remote_workflow/remote_step/rest.rb +3 -1
  114. data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +14 -5
  115. data/lib/rbbt/workflow/remote_workflow/remote_step.rb +19 -7
  116. data/lib/rbbt/workflow/remote_workflow.rb +6 -1
  117. data/lib/rbbt/workflow/step/run.rb +766 -766
  118. data/lib/rbbt/workflow/step/save_load_inputs.rb +254 -254
  119. data/lib/rbbt/workflow/step.rb +2 -362
  120. data/lib/rbbt/workflow/task.rb +118 -118
  121. data/lib/rbbt/workflow/usage.rb +289 -287
  122. data/lib/rbbt/workflow/util/archive.rb +6 -5
  123. data/lib/rbbt/workflow/util/data.rb +1 -1
  124. data/lib/rbbt/workflow/util/orchestrator.rb +249 -246
  125. data/lib/rbbt/workflow/util/trace.rb +79 -44
  126. data/lib/rbbt/workflow.rb +4 -882
  127. data/lib/rbbt-util.rb +21 -13
  128. data/lib/rbbt.rb +16 -3
  129. data/python/rbbt/__init__.py +19 -1
  130. data/share/Rlib/plot.R +37 -37
  131. data/share/Rlib/svg.R +22 -5
  132. data/share/install/software/lib/install_helpers +1 -1
  133. data/share/rbbt_commands/hpc/list +2 -3
  134. data/share/rbbt_commands/hpc/orchestrate +4 -4
  135. data/share/rbbt_commands/hpc/tail +2 -0
  136. data/share/rbbt_commands/hpc/task +10 -7
  137. data/share/rbbt_commands/lsf/list +2 -3
  138. data/share/rbbt_commands/lsf/orchestrate +4 -4
  139. data/share/rbbt_commands/lsf/tail +2 -0
  140. data/share/rbbt_commands/lsf/task +10 -7
  141. data/share/rbbt_commands/migrate +1 -1
  142. data/share/rbbt_commands/pbs/list +2 -3
  143. data/share/rbbt_commands/pbs/orchestrate +4 -4
  144. data/share/rbbt_commands/pbs/tail +2 -0
  145. data/share/rbbt_commands/pbs/task +10 -7
  146. data/share/rbbt_commands/resource/produce +8 -1
  147. data/share/rbbt_commands/slurm/list +2 -3
  148. data/share/rbbt_commands/slurm/orchestrate +4 -4
  149. data/share/rbbt_commands/slurm/tail +2 -0
  150. data/share/rbbt_commands/slurm/task +10 -7
  151. data/share/rbbt_commands/system/clean +5 -5
  152. data/share/rbbt_commands/system/status +5 -5
  153. data/share/rbbt_commands/tsv/get +2 -3
  154. data/share/rbbt_commands/tsv/info +10 -13
  155. data/share/rbbt_commands/tsv/keys +18 -14
  156. data/share/rbbt_commands/tsv/slice +2 -2
  157. data/share/rbbt_commands/tsv/transpose +6 -2
  158. data/share/rbbt_commands/workflow/info +20 -24
  159. data/share/rbbt_commands/workflow/list +1 -1
  160. data/share/rbbt_commands/workflow/prov +20 -13
  161. data/share/rbbt_commands/workflow/server +11 -1
  162. data/share/rbbt_commands/workflow/task +76 -71
  163. data/share/rbbt_commands/workflow/write_info +26 -9
  164. data/share/software/opt/ssw/ssw.c +861 -0
  165. data/share/software/opt/ssw/ssw.h +130 -0
  166. data/share/workflow_config.ru +3 -3
  167. metadata +40 -2
@@ -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