Class: Indexer::Metadata

Inherits:
Model
  • Object
show all
Extended by:
Loadable
Includes:
Attributes, Conversion
Defined in:
lib/indexer/metadata.rb

Overview

Conventional interface for specification provides convenience for developers. It offers method aliases and models various parts of the specification with useful classes.

Instance Attribute Summary

Attributes included from Attributes

#alternatives, #authors, #categories, #codename, #conflicts, #copyrights, #created, #date, #description, #engines, #install_message, #load_path, #name, #namespace, #organizations, #platforms, #repositories, #requirements, #resources, #revision, #sources, #suite, #summary, #title, #type, #version, #webcvs

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Loadable

exist?, exists?, find, import, load, load_file, lock, lock!, lock_file_missing, open, read, root

Methods included from Conversion

#import_gemfile, #import_gemspec, #to_gemspec

Methods included from Attributes

attr_accessor, #attributes

Methods inherited from Model

#[], #[]=, attr_reader, attr_writer, #initialize, #key?, #merge!, #method_missing, #to_yaml

Constructor Details

This class inherits a constructor from Indexer::Model

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Indexer::Model

Class Method Details

.from_gemspec(gemspec) ⇒ Object

Create a new Meta::Spec given a Gem::Specification or .gemspec file.

Parameters:

  • gemspec (Gem::Specification, String)

    RubyGems Gem::Specification object or path to .gemspec file.



59
60
61
# File 'lib/indexer/metadata.rb', line 59

def self.from_gemspec(gemspec)
  new.import_gemspec(gemspec)
end

.new(data = {}) ⇒ Object

Revision factory returns a versioned instance of the model class.

Parameters:

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

    The data to populate the instance.



29
30
31
32
# File 'lib/indexer/metadata.rb', line 29

def self.new(data={})
  data = revise(data)
  super(data)
end

.revise(data) ⇒ Object

Update metadata to current revision if using old revision.



49
50
51
# File 'lib/indexer/metadata.rb', line 49

def self.revise(data)
  Revision.upconvert(data)
end

.valid(data) ⇒ Object

Load metadata, ensuring canoncial validity.

Parameters:

  • data (String)

    The data to be validate and then to populate the instance.



40
41
42
43
44
# File 'lib/indexer/metadata.rb', line 40

def self.valid(data)
  data = revise(data)
  data = Validator.new(data).to_h
  create(data)
end

Instance Method Details

#about(*parts) ⇒ String

Create nicely formated project “about” text.

Returns:

  • (String)

    Formatted about text.



824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
# File 'lib/indexer/metadata.rb', line 824

def about(*parts)
  s = []
  parts = [:header, :description, :resources, :copyright] if parts.empty?
  parts.each do |part|
    case part.to_sym
    when :header
      s << "%s %s (%s-%s)" % [title, version, name, version]
    when :title
      s << title
    when :package
      s << "%s-%s" % [name, version]
    when :description
      s << description || summary
    when :summary
      s << summary
    when :resources
      s << resources.map{ |resource|
        "%s: %s" % [resource.label || resource.type, resource.uri]
      }.join("\n")
    when :repositories
      s << repositories.map{ |repo|
        "%s" % [repo.uri]
      }.join("\n")
    when :copyright, :copyrights
      s << copyrights.map{ |c|
        "Copyright (c) %s %s (%s)" % [c.year, c.holder, c.license]
      }.join("\n")
    else
      s << __send__(part)
    end
  end
  s.join("\n\n")
end

#add_alternative(name) ⇒ Object

Adds a new alternative.

Parameters:

  • name (String)

    The name of the alternative.



580
581
582
# File 'lib/indexer/metadata.rb', line 580

def add_alternative(name)
  alternatives << name.to_s
end

#add_conflict(name, specifics) ⇒ Object

Adds a new conflict.

Parameters:

  • name (String)

    The name of the conflict package.

  • specifics (Hash)

    The specifics of the conflict package.



570
571
572
# File 'lib/indexer/metadata.rb', line 570

def add_conflict(name, specifics)
  conflicts << Requirement.parse([name, specifics])
end

#add_repository(id, url, scm = nil) ⇒ Object



587
588
589
# File 'lib/indexer/metadata.rb', line 587

def add_repository(id, url, scm=nil)
  repositories << Repository.parse(:id=>id, :url=>url, :scm=>scm)
end

#add_requirement(name, specifics) ⇒ Object Also known as: add_dependency

Adds a new requirement.

Parameters:

  • name (String)

    The name of the requirement.

  • specifics (Hash)

    The specifics of the requirement.



546
547
548
# File 'lib/indexer/metadata.rb', line 546

def add_requirement(name, specifics)
  requirements << Requirement.parse([name, specifics])
end

#alternatives=(alternatives) ⇒ Object

Sets the packages this package could (more or less) replace.

Parameters:

  • alternatives (Array<String>)

    The alternatives for the project.



415
416
417
418
419
420
421
422
423
# File 'lib/indexer/metadata.rb', line 415

def alternatives=(alternatives)
  Valid.array!(alternatives, :alternatives)

  @data[:alternatives].clear

  alternatives.to_ary.each do |name|
    @data[:alternatives] << name.to_s
  end
end

#authors=(authors) ⇒ Object Also known as: author=

Set the authors of the project.

Parameters:

  • authors (Array<String>, String)

    The originating authors of the project.



282
283
284
285
286
287
288
289
290
# File 'lib/indexer/metadata.rb', line 282

def authors=(authors)
  @data[:authors] = (
    list = Array(authors).map do |a|
             Author.parse(a)
           end
    warn "Duplicate authors listed" if list != list.uniq
    list
  )
end

#categories=(categories) ⇒ Object

Sets the categories for this project.

Parameters:

  • categories (Array<String>)

    List of purpose categories for the project.



431
432
433
434
435
436
437
438
439
440
# File 'lib/indexer/metadata.rb', line 431

def categories=(categories)
  categories = Array(categories)

  @data[:categories].clear

  categories.to_ary.each do |name|
    Valid.oneline!(name.to_s)
    @data[:categories] << name.to_s
  end
end

#codename=(codename) ⇒ Object

Codename is the name of the particular version.



171
172
173
174
175
# File 'lib/indexer/metadata.rb', line 171

def codename=(codename)
  codename = codename.to_s if Symbol === codename
  Valid.oneline!(codename, :codename)
  @data[:codename] = codename.to_str
end

#conflicts=(conflicts) ⇒ Object

TODO:

lets get rid of the type check here and let the #parse method do it.

Sets the packages with which this package is known to have incompatibilites.

Parameters:

  • conflicts (Array<Hash>, Hash{String=>String})

    The conflicts for the project.

Raises:



397
398
399
400
401
402
403
404
405
406
407
# File 'lib/indexer/metadata.rb', line 397

def conflicts=(conflicts)
  case conflicts
  when Array, Hash
    @data[:conflicts].clear
    conflicts.each do |specifics|
      @data[:conflicts] << Conflict.parse(specifics)
    end
  else
    raise(ValidationError, "conflicts must be an Array or Hash")
  end
end

The primary copyright of the project.

Returns:

  • (String)

    The primary copyright for the project.



638
639
640
# File 'lib/indexer/metadata.rb', line 638

def copyright
  copyrights.join("\n")
end

#copyright=(copyright) ⇒ Object

Singular form of ‘#copyrights=`. This is similar to `#copyrights=` but expects the parameter to represent only one copyright.



259
260
261
# File 'lib/indexer/metadata.rb', line 259

def copyright=(copyright)
  @data[:copyrights] = [Copyright.parse(copyright)]
end

#copyrights=(copyrights) ⇒ Object

Set the copyrights and licenses for the project.

Copyrights SHOULD be in order of significance. The first license given is taken to be the project’s primary license.

License fields SHOULD be offically recognized identifiers such as “GPL-3.0” as defined by SPDX (http://).

Examples:

spec.copyrights = [ 
  {
    'year'    => '2010',
    'holder'  => 'Thomas T. Thomas',
    'license' => "MIT"
  }
]

Parameters:

  • The (Array<Hash,String,Array>)

    copyrights and licenses of the project.



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/indexer/metadata.rb', line 238

def copyrights=(copyrights)
  @data[:copyrights] = \
    case copyrights
    when String
      [Copyright.parse(copyrights, @_license)]
    when Hash
      [Copyright.parse(copyrights, @_license)]
    when Array
      copyrights.map do |copyright|
        Copyright.parse(copyright, @_license)
      end
    else
      raise(ValidationError, "copyright must be a String, Hash or Array")
    end
  @data[:copyrights]
end

#created=(date) ⇒ Object

Sets the creation date of the project.

Parameters:

  • date (String, Date, Time, DateTime)

    The creation date of this project.



205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/indexer/metadata.rb', line 205

def created=(date)
  @data[:created] = \
    case date
    when String
     Valid.utc_date!(date)
     Date.parse(date)
    when Date, Time, DateTime
     date
    else
     raise ValidationError, "invalid date for `created' - #{date.inspect}"
    end
end

#date=(date) ⇒ Object

Sets the production date of the project.

Parameters:

  • date (String, Date, Time, DateTime)

    The production date for this version.



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/indexer/metadata.rb', line 183

def date=(date)
  @data[:date] = \
    case date
    when String
      begin
        Date.parse(date)
      rescue ArgumentError
        raise ValidationError, "invalid date for `date' - #{date.inspect}"
      end
    when Date, Time, DateTime
      date
    else
      raise ValidationError, "invalid date for `date' - #{date.inspect}"
    end
end

#development_requirementsArray<Requirement>

Returns the development requirements of the project.

Returns:



693
694
695
696
697
# File 'lib/indexer/metadata.rb', line 693

def development_requirements
  requirements.select do |requirement|
    requirement.development?
  end
end

#emailString?

The primary email address of the project. The email address is taken from the first listed author.

Returns:

  • (String, nil)

    The primary email address for the project.



649
650
651
# File 'lib/indexer/metadata.rb', line 649

def email
  authors.find{ |a| a.email }
end

#engine=(value) ⇒ Object

Alternate singular form of #engines.



776
777
778
# File 'lib/indexer/metadata.rb', line 776

def engine=(value)
  self.engines = value
end

#engines=(value) ⇒ Object

List of language engine/version family supported.



336
337
338
339
340
341
342
# File 'lib/indexer/metadata.rb', line 336

def engines=(value)
  @data[:engines] = (
    a = [value].flatten
    a.each{ |x| Valid.oneline!(x) }
    a
  )
end

#external_development_requirementsArray<Requirement>

Returns the external development requirements of the project.

Returns:

  • (Array<Requirement>)

    external development requirements.



723
724
725
726
727
# File 'lib/indexer/metadata.rb', line 723

def external_development_requirements
  requirements.select do |requirement|
    requirement.external? && requirement.development?
  end
end

#external_requirementsArray<Requirement>

Returns the runtime requirements of the project.

Returns:



703
704
705
706
707
# File 'lib/indexer/metadata.rb', line 703

def external_requirements
  requirements.select do |requirement|
    requirement.external?
  end
end

#external_runtime_requirementsArray<Requirement>

Returns the external runtime requirements of the project.

Returns:

  • (Array<Requirement>)

    external runtime requirements.



713
714
715
716
717
# File 'lib/indexer/metadata.rb', line 713

def external_runtime_requirements
  requirements.select do |requirement|
    requirement.external? && requirement.runtime?
  end
end

#homepageObject Also known as: website

Get homepage URI.



656
657
658
659
660
661
662
663
# File 'lib/indexer/metadata.rb', line 656

def homepage #(uri=nil)
  #uri ? self.homepage = url
  resources.each do |r|
    if r.type == 'home'
      return r.uri
    end
  end
end

#homepage=(uri) ⇒ Object Also known as: website=

TODO:

Rename to website?

Convenience method for setting a ‘hompage` resource.



671
672
673
674
675
# File 'lib/indexer/metadata.rb', line 671

def homepage=(uri)
  resource = Resource.new(:name=>'homepage', :type=>'home', :uri=>uri)
  resources.unshift(resource)
  uri
end

#install_message=(message) ⇒ String

Sets the post-install message of the project.

Parameters:

  • message (Array, String)

    The post-installation message.

Returns:

  • (String)

    The new post-installation message.



514
515
516
517
518
519
520
521
522
523
# File 'lib/indexer/metadata.rb', line 514

def install_message=(message)
  @data[:install_message] = \
    case message
    when Array
      message.join($/)
    else
      Valid.string!(message)
      message.to_str
    end
end

#license=(license) ⇒ Object

Set copyright license for all copyright holders.



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

def license=(license)
  if copyrights = @data[:copyrights]
    copyrights.each do |c|
      c.license = license  # TODO: unless c.license ?
    end
  end
  @_license = license
end

#load_path=(paths) ⇒ Object

Sets the require paths of the project.

Parameters:

  • paths (Array<String>, String)

    The require-paths or a glob-pattern.



327
328
329
330
331
332
333
# File 'lib/indexer/metadata.rb', line 327

def load_path=(paths)
  @data[:load_path] = \
    Array(paths).map do |path|
      Valid.path!(path)
      path
    end
end

#loadpathArray

Returns load paths.

Returns:

  • (Array)

    load paths



734
735
736
# File 'lib/indexer/metadata.rb', line 734

def loadpath
  load_path
end

#loadpath=(value) ⇒ Object

RubyGems term for #load_path.



741
742
743
# File 'lib/indexer/metadata.rb', line 741

def loadpath=(value)
  self.load_path = value
end

#name=(name) ⇒ Object

Sets the name of the project.

Parameters:

  • name (String)

    The new name of the project.



103
104
105
106
107
108
109
# File 'lib/indexer/metadata.rb', line 103

def name=(name)
  name = name.to_s if Symbol === name
  Valid.name!(name, :name)
  @data[:name]  = name.to_str.downcase
  @data[:title] = @data[:name].capitalize unless @data[:title]  # TODO: use #titlecase
  @data[:name]
end

#namespace=(namespace) ⇒ Object

The toplevel namespace of API, e.g. ‘module Foo` or `class Bar`, would be `“Foo”` or `“Bar”`, repectively.

Parameters:

  • namespace (String)

    The new toplevel namespace of the project’s API.



127
128
129
130
# File 'lib/indexer/metadata.rb', line 127

def namespace=(namespace)
  Valid.constant!(namespace)
  @data[:namespace] = namespace
end

#organizations=(organizations) ⇒ Object Also known as: organization=, company=, companies, companies=

Set the orgnaization to which the project belongs.

Parameters:

  • organization (String)

    The name of the organization.



301
302
303
304
305
306
307
308
309
# File 'lib/indexer/metadata.rb', line 301

def organizations=(organizations)
  @data[:organizations] = (
    list = Array(organizations).map do |org|
             Organization.parse(org)
           end
    warn "Duplicate organizations listed" if list != list.uniq
    list
  )
end

#platform=(value) ⇒ Object

Alternate singular form of #platforms.



783
784
785
# File 'lib/indexer/metadata.rb', line 783

def platform=(value)
  self.platforms = value
end

#platforms=(value) ⇒ Object

Deprecated.

List of platforms supported.



349
350
351
352
353
354
355
# File 'lib/indexer/metadata.rb', line 349

def platforms=(value)
  @data[:platforms] = (
    a = [value].flatten
    a.each{ |x| Valid.oneline!(x) }
    a
  )
end

#repositories=(repositories) ⇒ Object

Sets the repostiories this project has.

Parameters:

  • repositories (Array<String>, Hash)

    The repositories for the project.



459
460
461
462
463
464
465
466
467
468
469
# File 'lib/indexer/metadata.rb', line 459

def repositories=(repositories)
  case repositories
  when Hash, Array
    @data[:repositories].clear
    repositories.each do |specifics|
      @data[:repositories] << Repository.parse(specifics)
    end
  else
    raise(ValidationError, "repositories must be an Array or Hash")
  end
end

#require_pathsArray

Returns load paths.

Returns:

  • (Array)

    load paths



748
749
750
# File 'lib/indexer/metadata.rb', line 748

def require_paths
  load_path
end

#require_paths=(value) ⇒ Object

RubyGems term for #load_path.



755
756
757
# File 'lib/indexer/metadata.rb', line 755

def require_paths=(value)
  self.load_path = value
end

#requirements=(requirements) ⇒ Object Also known as: dependencies=

Sets the requirements of the project. Also commonly called dependencies.

Parameters:

  • requirements (Array<Hash>, Hash{String=>Hash}, Hash{String=>String})

    The requirement details.

Raises:



366
367
368
369
370
371
372
373
374
375
376
377
# File 'lib/indexer/metadata.rb', line 366

def requirements=(requirements)
  requirements = [requirements] if String === requirements
  case requirements
  when Array, Hash
    @data[:requirements].clear
    requirements.each do |specifics|
      @data[:requirements] << Requirement.parse(specifics)
    end
  else
    raise(ValidationError,"requirements must be an Array or Hash")
  end
end

#requiresObject

Alternate short name for #requirements.



762
763
764
# File 'lib/indexer/metadata.rb', line 762

def requires
  requirements
end

#requires=(value) ⇒ Object

Alternate short name for #requirements.



769
770
771
# File 'lib/indexer/metadata.rb', line 769

def requires=(value)
  self.requirements = value
end

#resources=(resources) ⇒ Object

Set the resources for the project.

Parameters:

  • resources (Array, Hash)

    A list or map of resources.



477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/indexer/metadata.rb', line 477

def resources=(resources)
  case resources
  when Array
    @data[:resources].clear
    resources.each do |data|
      @data[:resources] << Resource.parse(data)
    end
  when Hash
    @data[:resources].clear
    resources.each do |type, uri|
      @data[:resources] << Resource.new(:uri=>uri, :type=>type.to_s)
    end
  else
    raise(ValidationError, "repositories must be an Array or Hash")
  end
end

#revision=(value) ⇒ Object

Set the revision. This is in a sense a dummy setting, since the actual revision is alwasy the latest.



70
71
72
# File 'lib/indexer/metadata.rb', line 70

def revision=(value)
  @data['revision'] = value.to_i
end

#runtime_requirementsArray<Requirement>

Returns the runtime requirements of the project.

Returns:



682
683
684
685
686
# File 'lib/indexer/metadata.rb', line 682

def runtime_requirements
  requirements.select do |requirement|
    requirement.runtime?
  end
end

#save!(file = LOCK_FILE) ⇒ Object

Save metadata lock file.

Parameters:

  • file (String) (defaults to: LOCK_FILE)

    The file name in which to save the metadata as YAML.



863
864
865
866
# File 'lib/indexer/metadata.rb', line 863

def save!(file=LOCK_FILE)
  v = Validator.new(to_h)
  v.save!(file)
end

#sources=(list) ⇒ Object Also known as: source=

Sources for building index file.

Parameters:

  • path(s) (String, Array)

    Paths from which metadata can be extracted.



89
90
91
# File 'lib/indexer/metadata.rb', line 89

def sources=(list)
  @data[:sources] = [list].flatten
end

#suite=(value) ⇒ Object

Suite must be a single line string.

Parameters:

  • suite (String)

    The suite to which the project belongs.



448
449
450
451
# File 'lib/indexer/metadata.rb', line 448

def suite=(value)
  Valid.oneline!(value, :suite)
  @data[:suite] = value
end

#summary=(summary) ⇒ Object

Summary is sanitized to only have one line of text.



135
136
137
138
# File 'lib/indexer/metadata.rb', line 135

def summary=(summary)
  Valid.string!(summary, :summary)
  @data[:summary] = summary.to_str.gsub(/\s+/, ' ')
end

#title=(title) ⇒ Object

Title is sanitized so that all white space is reduced to a single space character.



115
116
117
118
# File 'lib/indexer/metadata.rb', line 115

def title=(title)
  Valid.oneline!(title, :title)
  @data[:title] = title.to_str.gsub(/\s+/, ' ')
end

#to_hObject

Convert convenience form of metadata to canonical form.

@todo: A more robust means of insuring sources never self references.

@todo: Make sure this always generates the canonical form.



796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
# File 'lib/indexer/metadata.rb', line 796

def to_h
  date = self.date || Time.now

  h = super

  h['revision']      = REVISION
  h['sources' ]      = sources - ['.index']  # avoid self reference

  h['version']       = version.to_s

  h['date']          = date.strftime('%Y-%m-%d')
  h['created']       = created.strftime('%Y-%m-%d') if created

  h['authors']       = authors.map       { |x| x.to_h }
  h['organizations'] = organizations.map { |x| x.to_h }
  h['copyrights']    = copyrights.map    { |x| x.to_h }
  h['requirements']  = requirements.map  { |x| x.to_h }
  h['conflicts']     = conflicts.map     { |x| x.to_h }
  h['repositories']  = repositories.map  { |x| x.to_h }
  h['resources']     = resources.map     { |x| x.to_h }

  h
end

#type=(value) ⇒ Object

Set the revision. This is in a sense a dummy setting, since the actual revision is alwasy the latest.



78
79
80
81
# File 'lib/indexer/metadata.rb', line 78

def type=(value)
  Valid.type!(value, :type)
  @data['type'] = type.to_str
end

#valid?Boolean

A specification is not valid without a name and version.

Returns:

  • (Boolean)

    valid specification?



596
597
598
599
600
# File 'lib/indexer/metadata.rb', line 596

def valid?
  return false unless name
  return false unless version
  true
end

#version=(version) ⇒ Object

Sets the version of the project.

Parameters:

  • version (Hash, String, Array, Version::Number)

    The version from the metadata file.

Raises:

  • (ValidationError)

    The version must either be a ‘String`, `Hash` or `Array`.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/indexer/metadata.rb', line 149

def version=(version)
  case version
  when Version::Number
    @data[:version] = version
  when Hash
    major = version['major'] || version[:major]
    minor = version['minor'] || version[:minor]
    patch = version['patch'] || version[:patch]
    build = version['build'] || version[:build]
    @data[:version] = Version::Number.new(major,minor,patch,build)
  when String
    @data[:version] = Version::Number.parse(version.to_s)
  when Array
    @data[:version] = Version::Number.new(*version)
  else
    raise(ValidationError,"version must be a Hash or a String")
  end
end

#webcvs=(uri) ⇒ Object

The webcvs prefix must be a valid URI.

Parameters:

  • uri (String)

    The webcvs prefix, which must be a valid URI.



500
501
502
503
# File 'lib/indexer/metadata.rb', line 500

def webcvs=(uri)
  Valid.uri!(uri, :webcvs)
  @data[:webcvs] = uri
end