Module: Association::Index

Defined in:
lib/rbbt/association/index.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#source_fieldObject

Returns the value of attribute source_field.



119
120
121
# File 'lib/rbbt/association/index.rb', line 119

def source_field
  @source_field
end

#target_fieldObject

Returns the value of attribute target_field.



119
120
121
# File 'lib/rbbt/association/index.rb', line 119

def target_field
  @target_field
end

#undirectedObject

Returns the value of attribute undirected.



119
120
121
# File 'lib/rbbt/association/index.rb', line 119

def undirected
  @undirected
end

Class Method Details

.setup(repo) ⇒ Object



124
125
126
127
128
129
# File 'lib/rbbt/association/index.rb', line 124

def self.setup(repo)
  repo.extend Association::Index
  repo.parse_key_field
  repo.unnamed = true
  repo
end

Instance Method Details

#filter(value_field = nil, target_value = nil, &block) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/rbbt/association/index.rb', line 197

def filter(value_field = nil, target_value = nil, &block)
  if block_given?
    matches = []
    if value_field
      through :key, value_field do |key,values|
        pass = block.call values
        matches << key if pass
      end
    else
      through do |key,values|
        pass = block.call [key, values]
        matches << key if pass
      end
    end
    matches

  else
    matches = []
    if target_value
      target_value = [target_value] unless Array === target_value
      through :key, value_field do |key,values|
        pass = (values & target_value).any?
        matches << key if pass
      end
    else
      through :key, value_field do |key,values|
        pass = false
        values.each do |value|
          pass = true unless value.nil? or value.empty? or value.downcase == 'false'
        end
        matches << key if pass
      end
    end
    matches
  end
end

#match(entity) ⇒ Object



179
180
181
182
183
# File 'lib/rbbt/association/index.rb', line 179

def match(entity)
  return entity.inject([]){|acc,e| acc.concat match(e); acc } if Array === entity
  return [] if entity.nil?
  prefix(entity + "~")
end

#matches(entities) ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/rbbt/association/index.rb', line 185

def matches(entities)
  entities.inject(nil) do |acc,e| 
    m = match(e); 
    if acc.nil? or acc.empty?
      acc = m
    else
      acc.concat m
    end
    acc
  end
end

#parse_key_fieldObject



120
121
122
# File 'lib/rbbt/association/index.rb', line 120

def parse_key_field
  @source_field, @target_field, @undirected = key_field.split("~")
end

#reverseObject



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/rbbt/association/index.rb', line 131

def reverse
  @reverse ||= begin
                 if self.respond_to? :persistence_path
                   persistence_path = self.persistence_path
                   persistence_path = persistence_path.find if Path === persistence_path
                   reverse_filename = persistence_path + '.reverse'
                 else
                   raise "Can only reverse a TokyoCabinet::BDB dataset at the time"
                 end

                 if File.exist?(reverse_filename)
                   new = Persist.open_tokyocabinet(reverse_filename, false, serializer, TokyoCabinet::BDB)
                   raise "Index has no info: #{reverse_filename}" if new.key_field.nil?
                   Association::Index.setup new
                   new
                 else
                   FileUtils.mkdir_p File.dirname(reverse_filename) unless File.exist?(File.dirname(reverse_filename))

                   new = Persist.open_tokyocabinet(reverse_filename, true, serializer, TokyoCabinet::BDB)
                   
                   self.with_unnamed do
                     self.with_monitor :desc => "Reversing #{ persistence_path }" do
                       self.through do |key, value|
                         new_key = key.split("~").reverse.join("~")
                         new[new_key] = value
                       end
                     end
                   end
                   annotate(new)
                   new.key_field = key_field.split("~").values_at(1,0,2).compact * "~"
                   new.read_and_close do
                     Association::Index.setup new
                   end
                   new.read
                 end

                 new.unnamed = true

                 new.undirected = undirected

                 new
               rescue Exception
                 Log.error "Deleting after error reversing database: #{ reverse_filename }"
                 FileUtils.rm reverse_filename if File.exist? reverse_filename
                 raise $!
               end
end

#subset(source, target) ⇒ Object

{{{ Subset



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/rbbt/association/index.rb', line 256

def subset(source, target)
  return [] if source.nil? or target.nil? or source.empty? or target.empty?

  if source == :all or source == "all"
    if target == :all or target == "all"
      return keys
    else
      matches = reverse.subset(target, source)
      return matches.collect{|m| r = m.partition "~"; r.reverse*"" }
    end
  end

  matches = source.uniq.inject([]){|acc,e| 
    if block_given?
      acc.concat(match(e))
    else
      acc.concat(match(e))
    end
  }

  return matches if target == :all or target == "all"

  target_matches = {}

  matches.each{|code| 
    s,sep,t = code.partition "~"
    next if undirected and t > s and source.include? t
    target_matches[t] ||= []
    target_matches[t] << code
  }

  target_matches.values_at(*target.uniq).flatten.compact
end

#to_matrix(value_field = nil, &block) ⇒ Object



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/rbbt/association/index.rb', line 234

def to_matrix(value_field = nil, &block)
  value_field = fields.first if value_field.nil? and fields.length == 1
  value_pos = identify_field value_field if value_field and String === value_field
  key_field = source_field

  tsv = if value_pos
          AssociationItem.incidence self.keys, key_field do |key|
            if block_given? 
              yield self[key][value_pos]
            else
              self[key][value_pos]
            end
          end
        elsif block_given?
          AssociationItem.incidence self.keys, key_field, &block
        else
          AssociationItem.incidence self.keys, key_field 
        end
end