Module: Linguistics

Extended by:
Loggability
Includes:
ISO639
Defined in:
lib/linguistics.rb,
lib/linguistics/monkeypatches.rb

Overview

An interface for extending core Ruby classes with natural-language methods.

Defined Under Namespace

Modules: ArrayExtensions, EN, ISO639 Classes: Inflector

Constant Summary collapse

VERSION =

Release version

'2.1.0'
REVISION =

VCS version

%q$Revision: c4faf117867f $
DEFAULT_EXT_CLASSES =

The list of Classes to add linguistic behaviours to.

[ String, Numeric, Array ]

Constants included from ISO639

ISO639::LANGUAGE_CODES

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.inflector_mixinsObject (readonly)

The Hash of anonymous inflector modules that act as the mixin interface to a language module’s inflector, keyed by the language module they belong to



46
47
48
# File 'lib/linguistics.rb', line 46

def inflector_mixins
  @inflector_mixins
end

.languagesObject (readonly)

The Hash of loaded languages keyed by 3-letter bibliographic ISO639-2 code



42
43
44
# File 'lib/linguistics.rb', line 42

def languages
  @languages
end

Class Method Details

.load_language(lang) ⇒ Object

Try to load the module that implements the given language, returning the Module object if successful.



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
# File 'lib/linguistics.rb', line 89

def self::load_language( lang )
  unless mod = self.languages[ lang.to_sym ]

    self.log.debug "Trying to load language %p" % [ lang ]
    language = LANGUAGE_CODES[ lang.to_sym ] or
      raise "Unknown ISO639-2 language code '#{lang}'"
    self.log.debug "  got language code %p" % [ language ]

    # Sort all the codes for the specified language, trying the 2-letter
    # versions first in alphabetical order, then the 3-letter ones
    msgs = []
    mod = nil

    language[:codes].sort.each do |code|
      next if code == ''

      begin
        require "linguistics/#{code}"
        self.log.debug "  loaded linguistics/#{code}!"
        mod = self.languages[ lang.to_sym ]
        self.log.debug "  set mod to %p" % [ mod ]
        break
      rescue LoadError => err
        self.log.error "  require of linguistics/#{code} failed: #{err.message}"
        msgs << "Tried 'linguistics/#{code}': #{err.message}\n"
      end
    end

    if mod.is_a?( Array )
      raise LoadError,
        "Failed to load language extension %s:\n%s" %
        [ lang, msgs.join ]
    end

  end

  return mod
end

.make_inflector_mixin(lang, mod) ⇒ Object

Create a mixin module/class pair that act as the per-object interface to the given language mod‘s inflector.



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/linguistics.rb', line 177

def self::make_inflector_mixin( lang, mod )
  language = LANGUAGE_CODES[ lang.to_sym ] or
    raise "Unknown ISO639-2 language code '#{lang}'"

  unless mixin = self.inflector_mixins[ mod ]
    self.log.debug "Making an inflector mixin for %p" % [ mod ]

    bibcode, alpha2code, termcode = *language[:codes]
    inflector = Class.new( Linguistics::Inflector ) { include(mod) }
    self.log.debug "  created inflector class %p for [%p, %p, %p]" %
      [ inflector, bibcode, termcode, alpha2code ]

    mixin = Module.new do
      define_method( bibcode ) do
        inflector.new( bibcode, self )
      end
      alias_method termcode, bibcode unless termcode.nil? || termcode.empty?
      alias_method alpha2code, bibcode unless alpha2code.nil? || alpha2code.empty?
    end
    self.inflector_mixins[ mod ] = mixin
  end

  return mixin
end

.register_language(language, mod) ⇒ Object

Register a module as providing linguistic functions for the specified language (a two- or three-letter ISO639-2 language codes as a Symbol)



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
# File 'lib/linguistics.rb', line 60

def self::register_language( language, mod )
  language_entry = LANGUAGE_CODES[ language.to_sym ] or
    raise "Unknown ISO639-2 language code '#{language}'"
  self.log.info "Registering %s for language %p" % [ mod, language_entry ]

  language_entry[:codes].each do |lang|
    self.languages[ lang.to_sym ] = mod
  end

  # Load in plugins for the language
  Gem.find_files( "linguistics/#{language}/*.rb" ).each do |extension|
    next if extension.include?( '/spec/' ) # Skip specs
    extension.sub!( %r{.*/linguistics/}, 'linguistics/' )
    self.log.debug "  trying to load #{language_entry[:eng_name]} extension %p" % [ extension ]
    begin
      require extension
    rescue LoadError => err
      self.log.debug "    failed (%s): %s %s" %
        [ err.class.name, err.message, err.backtrace.first ]
    else
      self.log.debug "    success."
    end
  end

end

.use(*languages) ⇒ Object

Add linguistics functions for the specified languages to Ruby’s core classes. The interface to all linguistic functions for a given language is through a method which is the same the language’s international 2- or 3-letter code (ISO 639). You can also specify a Hash of configuration options which control which classes are extended:

:classes

Specify the classes which are to be extended. If this is not specified, the Class objects in Linguistics::DEFAULT_EXT_CLASSES (an Array) are extended.

:monkeypatch

Monkeypatch directly (albeit responsibly, via a mixin) the specified classes instead of adding a single language-code method.



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
# File 'lib/linguistics.rb', line 142

def self::use( *languages )
  config = languages.pop if languages.last.is_a?( Hash )
  config ||= {}

  classes = Array(config[:classes]) if config[:classes]
  classes ||= DEFAULT_EXT_CLASSES

  self.log.debug "Extending %d classes with %d language modules." %
    [ classes.length, languages.length ]

  # Mix the language module for each requested language into each
  # specified class
  classes.each do |klass|
    self.log.debug "  extending %p" % [ klass ]
    languages.each do |lang|
      mod = load_language( lang ) or
        raise LoadError, "failed to load a language extension for %p" % [ lang ]
      self.log.debug "    using %s language module: %p" % [ lang, mod ]

      if config[:monkeypatch]
        klass.send( :include, mod )
      else
        inflector = make_inflector_mixin( lang, mod )
        self.log.debug "    made an inflector mixin: %p" % [ inflector ]
        klass.send( :include, inflector )
      end
    end
  end

  return classes
end

.version_string(include_buildnum = false) ⇒ Object

Return the library’s version string



51
52
53
54
55
# File 'lib/linguistics.rb', line 51

def self::version_string( include_buildnum=false )
  vstring = "%s %s" % [ self.name, VERSION ]
  vstring << " (build %s)" % [ REVISION[/: ([[:xdigit:]]+)/, 1] || '0' ] if include_buildnum
  return vstring
end