Class: KnowledgeBase

Inherits:
Object
  • Object
show all
Defined in:
lib/scout/knowledge_base.rb,
lib/scout/knowledge_base/list.rb,
lib/scout/knowledge_base/query.rb,
lib/scout/knowledge_base/entity.rb,
lib/scout/knowledge_base/registry.rb,
lib/scout/knowledge_base/traverse.rb,
lib/scout/knowledge_base/enrichment.rb,
lib/scout/knowledge_base/description.rb

Overview

require ‘scout/knowledge_base/syndicate’

Defined Under Namespace

Classes: Traverser

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir, namespace = nil) ⇒ KnowledgeBase

Returns a new instance of KnowledgeBase.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/scout/knowledge_base.rb', line 16

def initialize(dir, namespace = nil)
  @dir = Path.setup(dir.dup)

  @namespace = namespace

  @identifier_files = []

  @registry       ||= IndiferentHash.setup({})
  @entity_options ||= IndiferentHash.setup({})

  @format         ||= IndiferentHash.setup({})
  pairs          ||= IndiferentHash.setup({})
  @indices        ||= IndiferentHash.setup({})
end

Instance Attribute Details

#dirObject

Returns the value of attribute dir.



14
15
16
# File 'lib/scout/knowledge_base.rb', line 14

def dir
  @dir
end

#entity_optionsObject

Returns the value of attribute entity_options.



14
15
16
# File 'lib/scout/knowledge_base.rb', line 14

def entity_options
  @entity_options
end

#formatObject

Returns the value of attribute format.



14
15
16
# File 'lib/scout/knowledge_base.rb', line 14

def format
  @format
end

#identifier_filesObject

Returns the value of attribute identifier_files.



14
15
16
# File 'lib/scout/knowledge_base.rb', line 14

def identifier_files
  @identifier_files
end

#namespaceObject

Returns the value of attribute namespace.



14
15
16
# File 'lib/scout/knowledge_base.rb', line 14

def namespace
  @namespace
end

#registryObject

Returns the value of attribute registry.



14
15
16
# File 'lib/scout/knowledge_base.rb', line 14

def registry
  @registry
end

Class Method Details

.doc_parse_chunks(str, pattern) ⇒ Object



11
12
13
14
15
16
17
18
# File 'lib/scout/knowledge_base/description.rb', line 11

def self.doc_parse_chunks(str, pattern)
  parts = str.split(pattern)
  return {} if parts.length < 2
  databases = Hash[*parts[1..-1].collect{|v| v.strip }]
  databases.delete_if{|t,d| d.empty?}
  databases.transform_keys!(&:downcase)
  databases
end

.doc_parse_up_to(str, pattern, keep = false) ⇒ Object



2
3
4
5
6
7
8
9
# File 'lib/scout/knowledge_base/description.rb', line 2

def self.doc_parse_up_to(str, pattern, keep = false)
  pre, _pat, _post = str.partition pattern
  if _pat
    [pre, (keep ? _pat << _post : _post)]
  else
    _post
  end
end

.load(dir) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/scout/knowledge_base.rb', line 61

def self.load(dir)
  kb = case dir
       when Path
         KnowledgeBase.new dir
       when Symbol
         dir = Path.setup("var").knowledge_base[dir.to_s] if Symbol === dir
         kb = KnowledgeBase.new dir
       when Workflow
         raise if dir.knowledge_base.nil?
         kb = dir.knowledge_base
       when String
         if Workflow.list.include? dir
           workflow = Workflow.require_workflow dir
           kb = workflow.knowledge_base
         elsif dir =~ /^\w+$/
           load(dir.to_sym)
         else
           kb = KnowledgeBase.new dir
         end
       end

  kb.load
  kb
end

.parse_knowledge_base_doc(doc) ⇒ Object



20
21
22
23
24
# File 'lib/scout/knowledge_base/description.rb', line 20

def self.parse_knowledge_base_doc(doc)
  description, db_description = doc_parse_up_to doc, /^#/, true
  databases = doc_parse_chunks db_description, /^# (.*)/ 
  IndiferentHash.setup({:description => description.strip, :databases => databases})
end

Instance Method Details

#_children(name, entity) ⇒ Object



59
60
61
62
# File 'lib/scout/knowledge_base/query.rb', line 59

def _children(name, entity)
  repo = get_index name
  repo.match(entity)
end

#_neighbours(name, entity) ⇒ Object



81
82
83
84
85
86
87
# File 'lib/scout/knowledge_base/query.rb', line 81

def _neighbours(name, entity)
  if undirected(name) and source(name) == target(name)
    {:children => _children(name, entity)}
  else
    {:parents => _parents(name, entity), :children => _children(name, entity)}
  end
end

#_parents(name, entity) ⇒ Object



69
70
71
72
# File 'lib/scout/knowledge_base/query.rb', line 69

def _parents(name, entity)
  repo = get_index name
  repo.reverse.match(entity)
end

#_subset(name, source = :all, target = :all, options = {}) ⇒ Object



9
10
11
12
13
# File 'lib/scout/knowledge_base/query.rb', line 9

def _subset(name, source = :all, target = :all, options = {})
  repo = get_index name, options

  repo.subset(source, target)
end

#all(name, options = {}) ⇒ Object



54
55
56
57
# File 'lib/scout/knowledge_base/query.rb', line 54

def all(name, options={})
  repo = get_index name, options
  setup name, repo.keys
end

#all_databasesObject



22
23
24
25
# File 'lib/scout/knowledge_base/registry.rb', line 22

def all_databases
  return [] unless @registry
  (@registry.keys + present_databases).uniq
end

#annotate(entities, type, database = nil) ⇒ Object



36
37
38
39
40
# File 'lib/scout/knowledge_base/entity.rb', line 36

def annotate(entities, type, database = nil)
  format = @format[type] || type
  entity_options = entity_options_for(type, database)
  Entity.prepare_entity(entities, format, entity_options)
end

#children(name, entity) ⇒ Object



64
65
66
67
# File 'lib/scout/knowledge_base/query.rb', line 64

def children(name, entity)
  entity = identify_source(name, entity)
  setup(name, _children(name, entity))
end

#config_file(name) ⇒ Object



31
32
33
# File 'lib/scout/knowledge_base.rb', line 31

def config_file(name)
  @dir['config'][name.to_s]
end

#database_description_file(name) ⇒ Object



36
37
38
# File 'lib/scout/knowledge_base/description.rb', line 36

def database_description_file(name)
  dir[name.to_s + '.md']
end

#database_file(name) ⇒ Object



27
28
29
30
31
32
33
# File 'lib/scout/knowledge_base/registry.rb', line 27

def database_file(name)
  if @registry[name].nil?
    nil
  else
    @registry[name].first
  end
end

#database_identifier_files(name) ⇒ Object



66
67
68
# File 'lib/scout/knowledge_base/entity.rb', line 66

def database_identifier_files(name)
  get_database(name).identifier_files.dup + self.identifier_files
end

#db_namespace(name) ⇒ Object



70
71
72
# File 'lib/scout/knowledge_base/entity.rb', line 70

def db_namespace(name)
  get_database(name).namespace
end

#define_entity_modulesObject



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/scout/knowledge_base/entity.rb', line 152

def define_entity_modules
  entity_options.each do |entity,options|
    next unless options[:identifiers]
    identifiers = options[:identifiers]
    identifiers = identifiers.split(",") unless Array === identifiers
    m = begin
          Object.const_get entity
        rescue
          m = Module.new
          m.extend Entity
          m.include Entity::Identified
          Object.const_set entity, m
        end

    identifiers.each do |file|
      m.add_identifiers Path.setup(file), self.format
    end
  end
end

#delete_list(id, entity_type = nil) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/scout/knowledge_base/list.rb', line 86

def delete_list(id, entity_type = nil)
  path = list_file(id, entity_type)
  path = list_file(id) unless path.exists?

  "This list does not belong to #{ user }: #{[entity_type, id] * ": "}" unless File.exist? path

  Open.lock path do
    begin
      FileUtils.rm path if File.exist? path
    rescue
      raise $!
    end
  end
end

#description(name) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/scout/knowledge_base/description.rb', line 50

def description(name)
  return registered_options(name)[:description] if registered_options(name)[:description]
  
  return database_description_file(name).read if database_description_file(name).exist? 

  if knowledge_base_description_file(name)
    KnowledgeBase.parse_knowledge_base_doc(knowledge_base_description_file(name).read)[:databases][name.to_s.downcase]
  end
end

#documentation_markdownObject



26
27
28
29
30
31
32
33
34
# File 'lib/scout/knowledge_base/description.rb', line 26

def documentation_markdown
  return "" if @libdir.nil?
  file = @libdir['README.md'].find unless file.exists?
  if file.exists?
    file.read
  else
    ""
  end
end

#enrichment(name, entities, options = {}) ⇒ Object



3
4
5
6
7
8
# File 'lib/scout/knowledge_base/enrichment.rb', line 3

def enrichment(name, entities, options = {})
  require 'rbbt/statistics/hypergeometric'
  database = get_database(name, options)
  entities = identify_source name, entities
  database.enrichment entities, database.fields.first, :persist => false
end

#entitiesObject



58
59
60
# File 'lib/scout/knowledge_base/entity.rb', line 58

def entities
  all_databases.inject([]){|acc,name| acc << source(name); acc << target(name)}.uniq
end

#entity_options_for(type, database_name = nil) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/scout/knowledge_base/entity.rb', line 20

def entity_options_for(type, database_name = nil)
  entity_options = self.entity_options
  IndiferentHash.setup entity_options if entity_options and not IndiferentHash === entity_options
  options = entity_options[type.to_s] || entity_options[Entity.formats[type].to_s] || {}
  options[:format] = @format[type] if Hash === @format && @format.include?(type)
  namespace = self.namespace
  namespace = db_namespace(database_name) if namespace.nil? and database_name
  if database_name  
    database = get_database(database_name)
    if database.entity_options and (database.entity_options[type] or database.entity_options[Entity.formats[type.to_s].to_s])
      options = options.merge(database.entity_options[type] || database.entity_options[Entity.formats[type.to_s].to_s])
    end
  end
  options
end

#entity_typesObject



62
63
64
# File 'lib/scout/knowledge_base/entity.rb', line 62

def entity_types
  entities.collect{|entity| Entity.formats[entity] }.uniq
end

#fields(name) ⇒ Object



47
48
49
50
# File 'lib/scout/knowledge_base/registry.rb', line 47

def fields(name)
  @fields ||= {}
  @fields[name] ||= get_index(name).fields
end

#get_database(name, options = {}) ⇒ Object



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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/scout/knowledge_base/registry.rb', line 131

def get_database(name, options = {})
  options = options.dup
  if self.namespace == options[:namespace]
    options.delete(:namespace) 
  end
  @databases ||= IndiferentHash.setup({})
  @databases[[name, options]] ||= 
    begin 
      fp = Log.fingerprint([name,options])

      if options.empty?
        key = name.to_s
      else
        fp = Misc.digest(options)
        key = name.to_s + "_" + fp
      end

      options[:namespace] ||= self.namespace unless self.namespace.nil?

      key += '.database'
      Persist.memory("Database:" + [key, dir] * "@") do
        options = options.dup

        persist_dir = dir
        persist_path = persist_dir[key].find

        file = database_file(name)
        registered_options = registered_options(name)
        registered_options =  IndiferentHash.setup(registered_options).except(:description)

        registered_options = IndiferentHash.add_defaults registered_options, identifiers: self.identifier_files if registered_options

        options = IndiferentHash.add_defaults options, registered_options if registered_options and registered_options.any?
        options = IndiferentHash.add_defaults options, :persist_path => persist_path, :persist => true

        if entity_options
          options[:entity_options] ||= {}
          entity_options.each do |type, info|
            options[:entity_options][type] ||= {}
            options[:entity_options][type] = IndiferentHash.add_defaults options[:entity_options][type], info
          end
        end

        persist_options = IndiferentHash.pull_keys options, :persist

        database = if persist_path.exists? and persist_options[:persist] and not persist_options[:update]
                     Log.low "Re-opening database #{ name } from #{ Log.fingerprint persist_path }. #{options}"
                     Association.database(file, **options.merge(persist_options: persist_options).except(:undirected))
                   else
                     options = IndiferentHash.add_defaults options, registered_options if registered_options
                     raise "Repo #{ name } not found and not registered" if file.nil?
                     Log.medium "Opening database #{ name } from #{ Log.fingerprint file }. #{options}"
                     file = file.call if Proc === file
                     Association.database(file, **options.merge(persist_options: persist_options).except(:undirected))
                   end

        database.namespace = self.namespace if self.namespace

        database
      end
    end
end

#get_index(name, options = {}) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/scout/knowledge_base/registry.rb', line 71

def get_index(name, options = {})
  name = name.to_s
  options[:namespace] ||= self.namespace unless self.namespace.nil?
  @indices ||= IndiferentHash.setup({})
  @indices[[name, options]] ||= 
    begin 
      if options.empty?
        key = name.to_s
      elsif options[:key]
        key = options[:key]
        key = name if key == :name
      else
        fp = Misc.digest(options)
        key = name.to_s + "_" + fp
      end

      Persist.memory("Index:" + [key, dir] * "@") do
        options = options.dup

        persist_dir = dir
        persist_path = persist_dir[key].find

        file = database_file(name)
        registered_options = registered_options(name)
        registered_options =  IndiferentHash.setup(registered_options).except(:description)

        registered_options = IndiferentHash.add_defaults registered_options, identifiers: self.identifier_files if registered_options

        options = IndiferentHash.add_defaults options, registered_options if registered_options and registered_options.any?
        options = IndiferentHash.add_defaults options, :persist_path => persist_path, :persist_dir => persist_dir, :persist => true

        if entity_options
          options[:entity_options] ||= {}
          entity_options.each do |type, info|
            options[:entity_options][type] ||= {}
            options[:entity_options][type] = IndiferentHash.add_defaults options[:entity_options][type], info
          end
        end

        persist_options = IndiferentHash.pull_keys options, :persist
        persist_options = IndiferentHash.add_defaults persist_options

        index = if persist_path.exists? and persist_options[:persist] and not persist_options[:update]
                  Log.low "Re-opening index #{ name } from #{ Log.fingerprint persist_path }. #{options}"
                  Association.index(file, **options, persist_options: persist_options.dup)
                else
                  database = get_database name if file.nil?
                  file = file.call if Proc === file
                  Log.medium "Opening index #{ name } from #{ Log.fingerprint database }. #{options}"
                  options = IndiferentHash.add_defaults options, registered_options if registered_options
                  Association.index(file, **options, persist_options: persist_options.dup, database: database)
                end

        index.namespace = self.namespace unless self.namespace

        index
      end
    end
end

#identify(name, entity) ⇒ Object



148
149
150
# File 'lib/scout/knowledge_base/entity.rb', line 148

def identify(name, entity)
  identify_source(name, entity) || identify_target(name, entity)
end

#identify_source(name, entity) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/scout/knowledge_base/entity.rb', line 121

def identify_source(name, entity)
  return :all if entity == :all
  index = begin 
            source_index(name) 
          rescue 
            Log.exception $!
            nil
          end
  return entity if index.nil?
  if Array === entity
    entity.collect{|e| index[e] || e }
  else
    index[entity] || entity
  end
end

#identify_target(name, entity) ⇒ Object



137
138
139
140
141
142
143
144
145
146
# File 'lib/scout/knowledge_base/entity.rb', line 137

def identify_target(name, entity)
  return :all if entity == :all
  index = begin target_index(name) rescue nil end
  return entity if index.nil?
  if Array === entity
    entity.collect{|e| index[e] || e }
  else
    index[entity] || entity
  end
end

#include?(name) ⇒ Boolean

Returns:

  • (Boolean)


43
44
45
# File 'lib/scout/knowledge_base/registry.rb', line 43

def include?(name)
  all_databases.include? name
end

#index_fields(name) ⇒ Object



194
195
196
# File 'lib/scout/knowledge_base/registry.rb', line 194

def index_fields(name)
  get_index(name).fields
end

#info(name) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/scout/knowledge_base.rb', line 86

def info(name)

  source = self.source(name)
  target = self.target(name)
  source_type = self.source_type(name)
  target_type = self.target_type(name)
  fields = self.fields(name)
  source_entity_options = self.entity_options_for source_type, name
  target_entity_options = self.entity_options_for target_type, name
  undirected = self.undirected(name) == 'undirected'

  info = {
    :source => source,
    :target => target,
    :source_type => source_type,
    :target_type => target_type,
    :source_entity_options => source_entity_options,
    :target_entity_options => target_entity_options,
    :fields => fields,
    :undirected => undirected,
  }

  info
end

#knowledge_base_description_file(name) ⇒ Object



40
41
42
43
44
45
46
47
48
# File 'lib/scout/knowledge_base/description.rb', line 40

def knowledge_base_description_file(name)
  file = dir['README.md']
  return file if file.exists?

  file, options = registry[name]
  file = Path.setup(file.dup) unless file.nil? or Path === file
  source_readme = file.dirname['README.md'] if file
  return source_readme if source_readme  && source_readme.exists?
end

#list_file(id, entity_type = nil) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/scout/knowledge_base/list.rb', line 4

def list_file(id, entity_type = nil)
  id = Path.sanitize_filename(id)

  entity_type = entity_type.to_s.split(":").last

  raise "Ilegal list id: #{ id }" unless Misc.path_relative_to(dir, File.join(dir, id))

  if entity_type
    if entity_type.to_s == "simple"
      path = dir.lists[entity_type.to_s][id]
    else
      path = dir.lists[entity_type.to_s][id].find_with_extension("tsv")
    end
  else
    path = dir.lists.glob("*/#{id}").first
    path ||= dir.lists.glob("*/#{id}.tsv").first
    raise "List not found #{id}" if path.nil?
  end

  path.find
end

#listsObject



76
77
78
79
80
81
82
83
84
# File 'lib/scout/knowledge_base/list.rb', line 76

def lists
  lists = {}
  dir.lists.glob("*").each do |list_dir|
    lists[list_dir.basename] = list_dir.glob("*").
      collect(&:unset_extension).
      collect(&:basename)
  end
  lists
end

#loadObject



54
55
56
57
58
59
# File 'lib/scout/knowledge_base.rb', line 54

def load
  load_variable(:namespace)
  load_variable(:registry)
  load_variable(:entity_options)
  load_variable(:identifier_files)
end

#load_list(id, entity_type = nil) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/scout/knowledge_base/list.rb', line 48

def load_list(id, entity_type = nil)
  if entity_type
    path = list_file(id, entity_type) 
    path = list_file(id) unless path.exists?
  else
    path = list_file(id)
  end

  raise "List not found: #{ id }" unless path and path.exists?

  begin
    if path.get_extension == 'tsv'
      list = Annotation.load_tsv path.tsv
      list.extend AnnotatedArray
      list
    else
      list = path.list
      if entity_type
        Entity.prepare_entity(list, entity_type)
      end
      list
    end
  rescue
    Log.exception $!
    nil
  end
end

#load_variable(name) ⇒ Object



41
42
43
44
45
# File 'lib/scout/knowledge_base.rb', line 41

def load_variable(name)
  file = config_file(name)
  variable = "@#{name}".to_sym
  self.instance_variable_set(variable, YAML.load(Open.read(file))) if file.exists?
end

#markdown(name) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/scout/knowledge_base/description.rb', line 60

def markdown(name)
  description = description(name)
  source_type = source_type(name)
  target_type = target_type(name)

  full_description = []
  empty_line = ''
  full_description << ("# " + Misc.humanize(name))
  full_description << empty_line

  source_formats = begin
                     source_index(name).key_field.split(',')
                   rescue
                     []
                   end

  target_formats = begin
                     target_index(name).key_field.split(',')
                   rescue
                     []
                   end

  if source_type 
    full_description << "Source: #{source_type} - #{source(name)}"
  else
    full_description << "Source: #{source(name)}"
  end
  #full_description.last << ". Accepted formats: #{source_formats*", "}" if source_formats.any?

  if target_type 
    full_description << "Target: #{target_type} - #{target(name)}"
  else
    full_description << "Target: #{target(name)}"
  end
  #full_description.last << ". Accepted formats: #{target_formats*", "}" if target_formats.any?
  
  if undirected?(name) 
    full_description << "Undirected database, source and target can be reversed."
  end

  if description
    full_description << empty_line
    full_description << description
    full_description << empty_line
  end

  full_description * "\n"
end

#neighbours(name, entity) ⇒ Object



89
90
91
92
93
94
95
# File 'lib/scout/knowledge_base/query.rb', line 89

def neighbours(name, entity)
  hash = _neighbours(name, entity)
  IndiferentHash.setup(hash)
  setup(name, hash[:children]) if hash[:children] 
  setup(name, hash[:parents], true) if hash[:parents]
  hash
end

#pair(name) ⇒ Object



52
53
54
55
# File 'lib/scout/knowledge_base/registry.rb', line 52

def pair(name)
  @pairs ||= {}
  @pairs[name] ||= get_index(name).key_field.split("~")
end

#parents(name, entity) ⇒ Object



74
75
76
77
78
79
# File 'lib/scout/knowledge_base/query.rb', line 74

def parents(name, entity)
  entity = identify_target(name, entity)
  matches = _parents(name, entity)
  #matches.each{|m| m.replace(m.partition("~").reverse*"") } unless undirected(name)
  setup(name, matches, true)
end

#present_databasesObject



18
19
20
# File 'lib/scout/knowledge_base/registry.rb', line 18

def present_databases
  dir.glob("*.database").collect{|file| File.basename(file, '.database')}
end

#produce(name, *rest, &block) ⇒ Object



198
199
200
201
# File 'lib/scout/knowledge_base/registry.rb', line 198

def produce(name, *rest,&block)
  register(name, *rest, &block)
  get_index(name)
end

#register(name, file = nil, options = {}, &block) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/scout/knowledge_base/registry.rb', line 5

def register(name, file = nil, options = {}, &block)
  file = file.find if Path === file
  @registry ||= IndiferentHash.setup({})
  if block_given?
    block.define_singleton_method(:filename) do name.to_s end
    Log.debug("Registering #{ name } from code block")
    @registry[name] = [block, options]
  else
    Log.debug("Registering #{ name }: #{ Log.fingerprint file } #{Log.fingerprint options}")
    @registry[name] = [file, options]
  end
end

#registered_options(name) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/scout/knowledge_base/registry.rb', line 35

def registered_options(name)
  if @registry[name].nil?
    IndiferentHash.setup({})
  else
    IndiferentHash.setup(@registry[name].last)
  end
end

#saveObject



47
48
49
50
51
52
# File 'lib/scout/knowledge_base.rb', line 47

def save
  save_variable(:namespace)
  save_variable(:registry)
  save_variable(:entity_options)
  save_variable(:identifier_files)
end

#save_list(id, list) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/scout/knowledge_base/list.rb', line 26

def save_list(id, list)
  if AnnotatedArray === list
    path = list_file(id, list.base_entity)
  else
    path = list_file(id, :simple)
  end

  Open.lock path do
    begin
      if AnnotatedArray === list
        path = path.set_extension('tsv')
        Open.write(path, Annotation.tsv(list, :all).to_s)
      else
        Open.write(path, list * "\n")
      end
    rescue
      FileUtils.rm(path) if File.exist?(path)
      raise $!
    end
  end
end

#save_variable(name) ⇒ Object



35
36
37
38
39
# File 'lib/scout/knowledge_base.rb', line 35

def save_variable(name)
  file = config_file(name)
  variable = "@#{name}".to_sym
  Open.write(file, self.instance_variable_get(variable).to_yaml)
end

#select_entities(name, entities, options = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/scout/knowledge_base/entity.rb', line 5

def select_entities(name, entities, options = {})
  index = get_index(name, options)

  source_field = index.source_field
  target_field = index.target_field

  source_type = source_type name
  target_type = target_type name

  source_entities = entities[:source] || entities[source_field] || entities[Entity.formats[source_field].to_s] || entities[:both]
  target_entities = entities[:target] || entities[target_field] || entities[Entity.formats[target_field].to_s] || entities[:both]

  [source_entities, target_entities]
end

#setup(name, matches, reverse = false) ⇒ Object



5
6
7
# File 'lib/scout/knowledge_base/query.rb', line 5

def setup(name, matches, reverse = false)
  AssociationItem.setup matches, self, name, reverse
end

#source(name) ⇒ Object



57
58
59
# File 'lib/scout/knowledge_base/registry.rb', line 57

def source(name)
  pair(name)[0]
end

#source_index(name) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/scout/knowledge_base/entity.rb', line 74

def source_index(name)
  Persist.memory("Source index #{name}: KB directory #{dir}") do
    if @identifier_files && @identifier_files.any?
      identifier_files = @identifier_files
    else
      identifier_files = database_identifier_files(name)
    end
    if registered_identifiers = registered_options(name)[:identifiers]
      if Array === registered_identifiers
        identifier_files.concat registered_identifiers
      else
        identifier_files.push registered_identifiers
      end
    end
    identifier_files.concat Entity.identifier_files(source(name)) if defined? Entity
    identifier_files.uniq!
    identifier_files.collect!{|f| (Path === f) ? f : Path.setup(f.dup) }
    identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, namespace))} if namespace
    identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, db_namespace(name)))} if not namespace and db_namespace(name)
    identifier_files.reject!{|f| f.match(/\bNAMESPACE\b/)}
    TSV.translation_index identifier_files, nil, source(name), :persist => true
  end
end

#source_type(name) ⇒ Object



50
51
52
# File 'lib/scout/knowledge_base/entity.rb', line 50

def source_type(name)
  Entity.formats[Entity.formats.find(source(name))]
end

#subset(name, entities, options = {}, &block) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/scout/knowledge_base/query.rb', line 15

def subset(name, entities, options = {}, &block)
  entities, options = options, entities if entities.nil? and Hash === options

  entities = case entities
             when :all
               {:target => :all, :source => :all}
             when AnnotatedArray
               format = entities.format if entities.respond_to? :format 
               format ||= entities.base_entity.to_s
               {format => entities.purge}
             when Hash
               entities
             else
               raise "Entities are not a Hash or an AnnotatedArray: #{Log.fingerprint entities}"
             end

  identify, identify_source, identify_target = entities.merge(options || {}).values_at :identify, :identify_source, :identify_target

  source, target = select_entities(name, entities, options)
  
  source = identify_source(name, source) if identify_source
  target = identify_target(name, target) if identify_target

  source = identify(name, source) if identify && !identify_source
  target = identify(name, target) if identify && !identify_target

  return [] if source.nil? or target.nil?
  return [] if Array === target and target.empty?
  return [] if Array === source and source.empty?

  matches = _subset name, source, target, options

  setup(name, matches)

  matches = matches.select(&block) if block_given? 

  matches
end

#target(name) ⇒ Object



61
62
63
# File 'lib/scout/knowledge_base/registry.rb', line 61

def target(name)
  pair(name)[1]
end

#target_index(name) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/scout/knowledge_base/entity.rb', line 98

def target_index(name)
  Persist.memory("Target index #{name}: KB directory #{dir}") do
    if @identifier_files && @identifier_files.any?
      identifier_files = @identifier_files
    else
      identifier_files = database_identifier_files(name)
    end
    if registered_identifiers = registered_options(name)[:identifiers]
      if Array === registered_identifiers
        identifier_files.concat registered_identifiers
      else
        identifier_files.push registered_identifiers
      end
    end
    identifier_files.concat Entity.identifier_files(target(name)) if defined? Entity
    identifier_files.uniq!
    identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, namespace))} if self.namespace
    identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, db_namespace(name)))} if namespace.nil? and db_namespace(name)
    identifier_files.reject!{|f| f.match(/\bNAMESPACE\b/)}
    TSV.translation_index identifier_files, nil, target(name), :persist => true
  end
end

#target_type(name) ⇒ Object



54
55
56
# File 'lib/scout/knowledge_base/entity.rb', line 54

def target_type(name)
  Entity.formats[Entity.formats.find(target(name))]
end

#translate(entities, type) ⇒ Object



42
43
44
45
46
47
48
# File 'lib/scout/knowledge_base/entity.rb', line 42

def translate(entities, type)
  if format = @format[type] and (entities.respond_to? :format and format != entities.format)
    entities.to format
  else
    entities
  end
end

#traverse(rules, nopaths = false) ⇒ Object



324
325
326
327
# File 'lib/scout/knowledge_base/traverse.rb', line 324

def traverse(rules, nopaths=false)
  traverser = KnowledgeBase::Traverser.new self, rules
  traverser.traverse nopaths
end

#undirected(name) ⇒ Object Also known as: undirected?



65
66
67
# File 'lib/scout/knowledge_base/registry.rb', line 65

def undirected(name)
  pair(name).length == 3
end