Class: Library

Inherits:
Object
  • Object
show all
Extended by:
Domain
Defined in:
lib/library.rb,
lib/library/domain.rb,
lib/library/errors.rb,
lib/library/ledger.rb,
lib/library/feature.rb,
lib/library/version.rb,
lib/library/metadata.rb

Overview

Library class encapsulates a location on disc that contains a Ruby project, with loadable features, of course.

Direct Known Subclasses

RubyLibrary

Defined Under Namespace

Modules: Domain Classes: Feature, Ledger, LoadError, Metadata, ValidationError, Version, VersionConflict, VersionError

Constant Summary collapse

SUFFIXES =

Possible suffixes for feature files, that #require will try automatically.

['.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
SUFFIX_PATTERN =

Extensions glob, joins extensions with comma and wrap in curly brackets.

"{#{SUFFIXES.join(',')}}"

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Domain

PATH, acquire, find_any, find_files, glob, ledger, load_stack, names, prime, search

Constructor Details

#initialize(location, metadata = {}) ⇒ Library

New Library object.

If data is given it must have ‘:name` and `:version`. It can also have `:loadpath`, `:date`, and `:omit`.

Parameters:

  • location (String)

    Expanded file path to library’s root directory.

  • metadata (Hash) (defaults to: {})

    Overriding matadata (to circumvent loading it from ‘.ruby` file).

Raises:

  • (TypeError)


117
118
119
120
121
122
123
124
125
# File 'lib/library.rb', line 117

def initialize(location, ={})
  raise TypeError, "not a directory - #{location}" unless File.directory?(location)

  @location = location
  @metadata = Metadata.new(location, )

  raise ValidationError, "Non-conforming library (missing name) -- `#{location}'" unless name
  raise ValidationError, "Non-conforming library (missing version) -- `#{location}'" unless version
end

Class Method Details

.[](name, constraint = nil) ⇒ Library, NilClass

A shortcut for #instance.

Returns:

  • (Library, NilClass)

    The activated Library instance, or ‘nil` if not found.



51
52
53
# File 'lib/library.rb', line 51

def self.[](name, constraint=nil)
  $LEDGER.activate(name, constraint) if $LEDGER.key?(name)
end

.activate(name, constraint = nil) {|library| ... } ⇒ Library

Activate a library. Same as #instance but will raise and error if the library is not found. This can also take a block to yield on the library.

Parameters:

  • name (String)

    Name of library.

  • constraint (String) (defaults to: nil)

    Valid version constraint.

Yields:

  • (library)

Returns:

  • (Library)

    The activated Library object.

Raises:



84
85
86
87
88
# File 'lib/library.rb', line 84

def self.activate(name, constraint=nil) #:yield:
  library = $LEDGER.activate(name, constraint)
  yield(library) if block_given?
  library
end

.add(location) ⇒ Library

TODO:

Better name for this method?

Like ‘#new`, but adds library to library ledger.

Returns:



97
98
99
100
101
102
103
# File 'lib/library.rb', line 97

def self.add(location)
  $LEDGER.add_location(location)

  #library = new(location)
  #$LEDGER.add_library(library)
  #library
end

.instance(name, constraint = nil) ⇒ Library, NilClass

TODO:

This method might be deprecated.

Get an instance of a library by name, or name and version. Libraries are singleton, so once loaded the same object is always returned.

Returns:

  • (Library, NilClass)

    The activated Library instance, or ‘nil` if not found.



64
65
66
# File 'lib/library.rb', line 64

def self.instance(name, constraint=nil)
  $LEDGER.activate(name, constraint) if $LEDGER.key?(name)
end

Instance Method Details

#<=>(other) ⇒ Object

Compare by version.



411
412
413
# File 'lib/library.rb', line 411

def <=>(other)
  version <=> other.version
end

#absolute_loadpathArray<String>

Returns a list of load paths expand to full path names.

Returns:

  • (Array<String>)

    list of expanded load paths



258
259
260
# File 'lib/library.rb', line 258

def absolute_loadpath
  loadpath.map{ |lp| ::File.join(location, lp) }
end

#activatetrue, false

Activate a library.

Returns:

  • (true, false)

    Has the library has been activated?



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/library.rb', line 132

def activate
  current = $LEDGER[name]

  if Library === current
    raise VersionConflict.new(self, current) if current != self
  else
    ## NOTE: we are only doing this for the sake of autoload
    ## which does not honor a customized require method.
    #if Library.autoload_hack?
    #  absolute_loadpath.each do |path|
    #    $LOAD_PATH.unshift(path)
    #  end
    #end
    $LEDGER[name] = self
  end

  # TODO: activate runtime requirements?
  #verify
end

#active?Boolean

Is this library active in global ledger?

Returns:

  • (Boolean)


155
156
157
# File 'lib/library.rb', line 155

def active?
  $LEDGER[name] == self
end

#bindirObject

Location of executable. This is alwasy bin/. This is a fixed convention, unlike lib/ which needs to be more flexable.



444
445
446
# File 'lib/library.rb', line 444

def bindir
  ::File.join(location, 'bin')
end

#bindir?Boolean

Is there a ‘bin/` location?

Returns:

  • (Boolean)


451
452
453
# File 'lib/library.rb', line 451

def bindir? 
  ::File.exist?(bindir)
end

#confdirObject

Location of library system configuration files. This is alwasy the ‘etc/` directory.



459
460
461
# File 'lib/library.rb', line 459

def confdir
  ::File.join(location, 'etc')
end

#confdir?Boolean

Is there a ‘etc/` location?

Returns:

  • (Boolean)


466
467
468
# File 'lib/library.rb', line 466

def confdir?
  ::File.exist?(confdir)
end

#datadirObject

Location of library shared data directory. This is always the ‘data/` directory.



472
473
474
# File 'lib/library.rb', line 472

def datadir
  ::File.join(location, 'data')
end

#datadir?Boolean

Is there a ‘data/` location?

Returns:

  • (Boolean)


477
478
479
# File 'lib/library.rb', line 477

def datadir?
  ::File.exist?(datadir)
end

#dateTime Also known as: released

Release date.

Returns:

  • (Time)

    library’s release date



211
212
213
# File 'lib/library.rb', line 211

def date
  .date
end

#defaultObject

Return default feature. This is the feature that has same name as the library itself.



419
420
421
# File 'lib/library.rb', line 419

def default
  @default ||= find(name, :main=>true)
end

#feature(lpath, pathname, ext = nil) ⇒ Object

Create a new Feature object from lpath, pathname and ext.



363
364
365
# File 'lib/library.rb', line 363

def feature(lpath, pathname, ext=nil)
  Feature.new(self, lpath, pathname, ext)
end

#find(pathname, options = {}) ⇒ Feature? Also known as: include?

Does a library contain a relative file within it’s loadpath. If so return the libary file object for it, otherwise false.

Note that this method was designed to maximize speed.

Parameters:

  • file (#to_s)

    The relative pathname of the file to find.

  • options (Hash) (defaults to: {})

    The Hash of optional settings to adjust search behavior.

Options Hash (options):

  • :suffix (Boolean)

    Automatically try standard extensions if pathname has none.

  • :legacy (Boolean) — default: deprecated

    Do not match within library’s name directory, eg. ‘lib/foo/*`.

Returns:

  • (Feature, nil)

    The feature, if found.



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/library.rb', line 297

def find(pathname, options={})
  main   = options[:main]
  #legacy = options[:legacy]
  suffix = options[:suffix] || options[:suffix].nil?
  #suffix = false if options[:load]
  suffix = false if SUFFIXES.include?(::File.extname(pathname))
  if suffix
    loadpath.each do |lpath|
      SUFFIXES.each do |ext|
        f = ::File.join(location, lpath, pathname + ext)
        return feature(lpath, pathname, ext) if ::File.file?(f)
      end
    end #unless legacy
    legacy_loadpath.each do |lpath|
      SUFFIXES.each do |ext|
        f = ::File.join(location, lpath, pathname + ext)
        return feature(lpath, pathname, ext) if ::File.file?(f)
      end
    end unless main
  else
    loadpath.each do |lpath|
      f = ::File.join(location, lpath, pathname)
      return feature(lpath, pathname) if ::File.file?(f)
    end #unless legacy
    legacy_loadpath.each do |lpath|
      f = ::File.join(location, lpath, pathname)        
      return feature(lpath, pathname) if ::File.file?(f)
    end unless main
  end
  nil
end

#inspectObject

Inspect library instance.



393
394
395
396
397
398
399
# File 'lib/library.rb', line 393

def inspect
  if version
    %[#<Library #{name}/#{version} @location="#{location}">]
  else
    %[#<Library #{name} @location="#{location}">]
  end
end

#legacy?Boolean

Returns:

  • (Boolean)


337
338
339
# File 'lib/library.rb', line 337

def legacy?
  !legacy_loadpath.empty?
end

#legacy_loadpathObject

What is ‘legacy_loadpath`? Well, library doesn’t require you to put your library’s scripts in a named lib path, e.g. ‘lib/foo/`. Instead one can just put them in `lib/` b/c Library keeps things indexed by honest to goodness library names. The `legacy_path` then is used to handle these old style paths along with the new.



348
349
350
351
352
353
354
355
356
357
358
# File 'lib/library.rb', line 348

def legacy_loadpath
  @legacy_loadpath ||= (
    path = []
    loadpath.each do |lp|
      llp = File.join(lp, name)
      dir = File.join(location, llp)
      path << llp if File.directory?(dir)
    end
    path
  )
end

#load(pathname, options = {}) ⇒ Object

Load feature form library.



381
382
383
384
385
386
387
388
# File 'lib/library.rb', line 381

def load(pathname, options={})
  #options[:load] = true
  if feature = find(pathname, options)
    feature.load(options)
  else
    raise LoadError.new(pathname, self.name)
  end
end

#load_pathArray Also known as: loadpath

Library’s internal load path(s). This will default to ‘[’lib’]‘ if not otherwise given.

Returns:

  • (Array)

    list of load paths



200
201
202
# File 'lib/library.rb', line 200

def load_path
  .load_path
end

#locationObject

Location of library files on disc.



162
163
164
# File 'lib/library.rb', line 162

def location
  @location
end

#metadataMetadata

Access to library metadata. Metadata is gathered from the ‘.ruby` file or a `.gemspec` file.

Returns:



172
173
174
# File 'lib/library.rb', line 172

def 
  @metadata
end

#nameString

Library’s “unixname”.

Returns:

  • (String)

    name of library



181
182
183
# File 'lib/library.rb', line 181

def name
  @name ||= .name
end

#omitBoolean Also known as: omit?

Omit library form ledger?

Returns:

  • (Boolean)

    if true, omit library from ledger



244
245
246
# File 'lib/library.rb', line 244

def omit
  @metadata.omit
end

#require(pathname, options = {}) ⇒ Object

Requre feature from library.



370
371
372
373
374
375
376
# File 'lib/library.rb', line 370

def require(pathname, options={})
  if feature = find(pathname, options)
    feature.require(options)
  else
    raise LoadError.new(path, name)  # TODO: silently?
  end
end

#requirementsArray

Library’s requirements. Note that in gemspec terminology these are called dependencies.

Returns:

  • (Array)

    list of requirements



226
227
228
# File 'lib/library.rb', line 226

def requirements
  .requirements
end

#runtime_requirementsArray

Runtime requirements.

Returns:

  • (Array)

    list of runtime requirements



235
236
237
# File 'lib/library.rb', line 235

def runtime_requirements
  requirements.select{ |req| !req['development'] }
end

#to_hHash

Convert to hash.

Returns:

  • (Hash)

    The library metadata in a hash.



491
492
493
494
495
496
497
498
499
500
# File 'lib/library.rb', line 491

def to_h
  {
    :location     => location,
    :name         => name,
    :version      => version.to_s,
    :loadpath     => loadpath,
    :date         => date.to_s,
    :requirements => requirements
  }
end

#to_sObject

Same as #inspect.



404
405
406
# File 'lib/library.rb', line 404

def to_s
  inspect
end

#verify(development = false) ⇒ Object

Take requirements and open them. This will reveal any version conflicts or missing dependencies.

Parameters:

  • development (Boolean) (defaults to: false)

    Include development dependencies?



269
270
271
272
273
274
275
# File 'lib/library.rb', line 269

def verify(development=false)
  reqs = development ? requirements : runtime_requirements
  reqs.each do |req|
    name, constraint = req['name'], req['version']
    Library.open(name, constraint)
  end
end

#versionVersionNumber

Library’s version number.

Returns:

  • (VersionNumber)

    version number



190
191
192
# File 'lib/library.rb', line 190

def version
  @version ||= .version
end