class Lingo

Constants

BASE

The system-wide Lingo directory (LINGO_BASE).

CURR

The local Lingo directory (LINGO_CURR).

ENCODING

Default encoding

FIND_OPTIONS

Map of file types to their standard location and file extension.

HOME

The user's personal Lingo directory (LINGO_HOME).

PATH

The search path for Lingo dictionary and configuration files.

SEP_RE
VERSION

Attributes

dictionaries[R]

Public Class Methods

CLI(args, extra = nil, &block) click to toggle source
# File lib/lingo/cli.rb, line 79
def self.CLI(args, extra = nil, &block)
  opt, req = args.partition { |arg| arg.sub!(/\?\z/, '') }

  unless (n = ARGV.size - req.size) >= 0 && n <= opt.size
    msg = "Usage: #{$0}#{args.map { |arg| [' ', arg].zip(
      opt.include?(arg) ? %w[[ ]] : %w[< >]).join }.join}"

    abort Array(extra).unshift(msg).join("\n\n")
  end

  Object.new.extend(TextUtils).instance_eval(&block)
rescue LingoError => err
  abort err.to_s
ensure
  ObjectSpace.each_object(Zlib::GzipWriter, &:close)
end
append_path(*path) click to toggle source
# File lib/lingo.rb, line 123
def append_path(*path)
  include_path(path)
end
basename(type, file) click to toggle source
# File lib/lingo.rb, line 114
def basename(type, file)
  dir, name = File.split(file)
  type != :dict ? name : File.join(File.basename(dir), name)
end
basepath(type, file) click to toggle source
# File lib/lingo.rb, line 119
def basepath(type, file)
  File.join(options_for(type)[:dir], basename(type, file))
end
call(cfg = find(:config, 'lingo-call'), args = [], &block) click to toggle source
# File lib/lingo.rb, line 79
def call(cfg = find(:config, 'lingo-call'), args = [], &block)
  Call.new(['-c', cfg, *args]).call(&block)
end
find(type, file, options = {}) { |err| ... } click to toggle source
# File lib/lingo.rb, line 99
def find(type, file, options = {})
  if options.is_a?(Array)
    path    = options
    options = options_for(type)
  else
    options = options_for(type, options)
    path    = path_for(options)
  end

  type = :file if type != :store
  send("find_#{type}", file, path, options)
rescue RuntimeError, Errno::ENOENT => err
  block_given? ? yield(err) : raise
end
get_const(name, klass = self) click to toggle source
# File lib/lingo.rb, line 131
def get_const(name, klass = self)
  klass.const_get(name.camelcase)
rescue NameError
  raise NameNotFoundError.new(klass, name)
end
list(type, options = {}) click to toggle source
# File lib/lingo.rb, line 83
def list(type, options = {})
  options = options_for(type, options)

  glob, list = file_with_ext('*', options), []
  glob = File.join('??', glob) if type == :dict

  walk(path = path_for(options), options) { |dir|
    Dir[File.join(dir, glob)].sort!.each { |file|
      pn = Pathname.new(file)
      list << realpath_for(pn, path) if pn.file?
    }
  }

  list
end
new(*args) click to toggle source
# File lib/lingo.rb, line 231
def initialize(*args)
  Debug.ps(:lingo_new)

  @config_args = args
  reset(false)
end
prepend_path(*path) click to toggle source
# File lib/lingo.rb, line 127
def prepend_path(*path)
  include_path(path, true)
end
talk(*args) click to toggle source
# File lib/lingo.rb, line 75
def talk(*args)
  new(*args).talk
end

Private Class Methods

file_with_ext(file, options) click to toggle source
# File lib/lingo.rb, line 204
def file_with_ext(file, options)
  ext = options[:ext]
  ext && File.extname(file).empty? ? "#{file}.#{ext}" : file
end
find_file(file, path, options) click to toggle source
# File lib/lingo.rb, line 143
def find_file(file, path, options)
  if glob = options[:glob]
    file = File.chomp_ext(file)
    options[:ext] ||= '*'
  end

  file = file_with_ext(file, options)
  pn   = Pathname.new(file).cleanpath

  if pn.relative?
    walk(path, options) { |dir|
      pn2 = pn.expand_path(dir)
      ex  = pn2.exist?

      pn2 = Pathname.glob(pn2).first if glob && !ex
      pn  = pn2 and break if glob ? pn2 : ex
    }
  end

  realpath_for(pn, path)
rescue Errno::ENOENT
  raise unless relax = options[:relax]
  relax.respond_to?(:[]) ? relax[file] : file
end
find_store(file, path, options) click to toggle source
# File lib/lingo.rb, line 168
def find_store(file, path, options)
  base = basename(:dict, find(:dict, file, path) {
    raise SourceFileNotFoundError.new(nil, find_file(file, path,
      options.merge(glob: true, relax: lambda { |_file|
        raise SourceFileNotFoundError.new(file, _file)
      })
    ))
  })

  walk(path.reverse, options, false) { |dir|
    Pathname.new(dir).ascend { |i|
      begin
        stat = i.stat

        break true if stat.file? || !stat.writable?
        return File.chomp_ext(File.join(dir, base))
      rescue Errno::ENOENT
      end
    }
  }

  raise NoWritableStoreError.new(file, path)
end
include_path(path, pre = false) click to toggle source
# File lib/lingo.rb, line 139
def include_path(path, pre = false)
  PATH.insert(pre ? 0 : -1, *path.map! { |i| i.to_s })
end
options_for(type, options = {}) click to toggle source
# File lib/lingo.rb, line 192
def options_for(type, options = {})
  if find_options = FIND_OPTIONS[type]
    options = find_options.merge(options)
  else
    raise ArgumentError, "Invalid type `#{type.inspect}'", caller(1)
  end
end
path_for(options) click to toggle source
# File lib/lingo.rb, line 200
def path_for(options)
  options[:path] || PATH
end
realpath_for(pn, path) click to toggle source
# File lib/lingo.rb, line 220
def realpath_for(pn, path)
  pn.realpath(path.first).to_s
end
require_optional(lib) click to toggle source
# File lib/lingo.rb, line 224
def require_optional(lib)
  require lib unless ENV["LINGO_NO_#{lib.upcase}"]
rescue LoadError
end
walk(path, options, legacy = true) { |join| ... } click to toggle source
# File lib/lingo.rb, line 209
def walk(path, options, legacy = true)
  dirs, seen = [options[:dir].to_s], Hash.seen
  dirs << '' if legacy
  dirs.uniq!

  path.each { |d|
    next if seen[d = File.expand_path(d)]
    dirs.each { |i| yield File.join(d, i) } or break
  }
end

Public Instance Methods

attendees(arg = Object) click to toggle source
# File lib/lingo.rb, line 305
def attendees(arg = Object)
  @attendees.grep(arg.is_a?(Class) ? arg :
    Attendee.const_get(arg.to_s.camelcase))
end
config() click to toggle source
# File lib/lingo.rb, line 240
def config
  @config ||= Config.new(*@config_args)
rescue => err
  raise ConfigLoadError.new(err)
end
database_config(id) click to toggle source
# File lib/lingo.rb, line 250
def database_config(id)
  dictionary_config['databases'][id].tap { |cfg|
    raise NoDatabaseConfigError.new(id) unless cfg
    raise InvalidDatabaseConfigError.new(id) unless cfg.key?('name')
  }
end
dictionary_config() click to toggle source
# File lib/lingo.rb, line 246
def dictionary_config
  @dictionary_config ||= config['language/dictionary']
end
invite(list = config['meeting/attendees']) click to toggle source
# File lib/lingo.rb, line 272
def invite(list = config['meeting/attendees'])
  supplier, subscriber = Hash.array, Hash.array

  last_link, auto_link = '', 0

  list.each { |hash|
    name = (name_key = hash.keys.first).camelcase

    cfg = (config["language/attendees/#{name.downcase}"] || {})
      .merge(hash.values.first).update('name' => name)

    %w[in out].each { |key| (cfg[key] ||= '').downcase! }

    cfg['in']  = last_link                     if cfg['in'].empty?
    cfg['out'] = "auto_link-#{auto_link += 1}" if cfg['out'].empty?
    last_link  = cfg['out']

    @attendees << attendee = Attendee.const_get(name).new(cfg, self)

    unless name == (real = attendee.class.name.split('::').last)
      config.deprecate(name_key, real.underscore, attendee, :name)
    end

    { 'in' => subscriber, 'out' => supplier }.each { |key, target|
      cfg[key].split(SEP_RE).each { |ch| target[ch] << attendee }
    }
  }

  supplier.each { |ch, attendees| attendees.each { |att|
    att.subscribers.concat(subscriber[ch])
  } }
end
lexical_hash(src) click to toggle source
# File lib/lingo.rb, line 257
def lexical_hash(src)
  @lexical_hash[src]
end
reset(close = true) click to toggle source
# File lib/lingo.rb, line 314
def reset(close = true)
  dictionaries.each { |i| i.close } if close
  @dictionaries, @attendees = [], []
  @lexical_hash = Hash.nest { |k| Language::LexicalHash.new(k, self) }
end
start() click to toggle source
# File lib/lingo.rb, line 310
def start
  @attendees.first.control(:TALK)
end
talk() click to toggle source
# File lib/lingo.rb, line 261
def talk
  Debug.profile(config['profile']) {
    invite
    start
  }

  Debug.ps(:lingo_talk)
ensure
  reset
end
warn(*msg) click to toggle source
# File lib/lingo.rb, line 320
def warn(*msg)
  config.warn(*msg)
end