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.



113
114
115
# File 'lib/rbbt/association/index.rb', line 113

def source_field
  @source_field
end

#target_fieldObject

Returns the value of attribute target_field.



113
114
115
# File 'lib/rbbt/association/index.rb', line 113

def target_field
  @target_field
end

#undirectedObject

Returns the value of attribute undirected.



113
114
115
# File 'lib/rbbt/association/index.rb', line 113

def undirected
  @undirected
end

Class Method Details

.setup(repo) ⇒ Object



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

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



191
192
193
194
195
196
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
# File 'lib/rbbt/association/index.rb', line 191

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



173
174
175
176
177
# File 'lib/rbbt/association/index.rb', line 173

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



179
180
181
182
183
184
185
186
187
188
189
# File 'lib/rbbt/association/index.rb', line 179

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



114
115
116
# File 'lib/rbbt/association/index.rb', line 114

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

#reverseObject



125
126
127
128
129
130
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
# File 'lib/rbbt/association/index.rb', line 125

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



250
251
252
253
254
255
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
# File 'lib/rbbt/association/index.rb', line 250

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



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/rbbt/association/index.rb', line 228

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