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, #customs, #date, #description, #engines, #install_message, #name, #namespace, #organizations, #paths, #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, #store, #to_yaml, #validate

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

.createObject (private)



20
# File 'lib/indexer/metadata.rb', line 20

alias :create :new

.from_gemspec(gemspec) ⇒ Object

Create a new Metadata instance 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.



847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
# File 'lib/indexer/metadata.rb', line 847

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.



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

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.



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

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

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



605
606
607
# File 'lib/indexer/metadata.rb', line 605

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.



564
565
566
# File 'lib/indexer/metadata.rb', line 564

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.



418
419
420
421
422
423
424
425
426
# File 'lib/indexer/metadata.rb', line 418

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.



434
435
436
437
438
439
440
441
442
443
# File 'lib/indexer/metadata.rb', line 434

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:



400
401
402
403
404
405
406
407
408
409
410
# File 'lib/indexer/metadata.rb', line 400

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.



656
657
658
# File 'lib/indexer/metadata.rb', line 656

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

#customs=(customs) ⇒ Object

Set custom user-field names.



531
532
533
534
535
536
537
# File 'lib/indexer/metadata.rb', line 531

def customs=(customs)
  #unless customs.kind_of?(Hash)
    #raise(ValidationError, "customs must be an Array")
    Valid.array!(customs)
  #end
  @data[:customs] = customs
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:



711
712
713
714
715
# File 'lib/indexer/metadata.rb', line 711

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.



667
668
669
# File 'lib/indexer/metadata.rb', line 667

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

#engine=(value) ⇒ Object

Alternate singular form of #engines.



794
795
796
# File 'lib/indexer/metadata.rb', line 794

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

#engines=(value) ⇒ Object

List of language engine/version family supported.



339
340
341
342
343
344
345
# File 'lib/indexer/metadata.rb', line 339

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.



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

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:



721
722
723
724
725
# File 'lib/indexer/metadata.rb', line 721

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.



731
732
733
734
735
# File 'lib/indexer/metadata.rb', line 731

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

#homepageObject Also known as: website

Get homepage URI.



674
675
676
677
678
679
680
681
# File 'lib/indexer/metadata.rb', line 674

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.



689
690
691
692
693
# File 'lib/indexer/metadata.rb', line 689

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.



517
518
519
520
521
522
523
524
525
526
# File 'lib/indexer/metadata.rb', line 517

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_pathObject

Legacy method to common Ruby path via paths['load'].



544
545
546
# File 'lib/indexer/metadata.rb', line 544

def load_path
  paths['lib']
end

#load_path=(path) ⇒ Object

Legacy method to set paths['load'].



551
552
553
# File 'lib/indexer/metadata.rb', line 551

def load_path=(path)
  paths['lib'] = Array(path).map{ |path| Valid.path!(path) }
end

#loadpathArray

Returns load paths.

Returns:

  • (Array)

    load paths



752
753
754
# File 'lib/indexer/metadata.rb', line 752

def loadpath
  load_path
end

#loadpath=(value) ⇒ Object

RubyGems term for #load_path.



759
760
761
# File 'lib/indexer/metadata.rb', line 759

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

#paths=(path_map) ⇒ Object

Sets the named paths of the project.

Parameters:

  • path_map (Hash[String]=Array<String>)

    Mappaing of names to list of paths.



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

def paths=(path_map)
  @data[:paths] = \
    map = {}
    path_map = path_map.to_hash if path_map.respond_to?(:to_hash)
    Valid.hash!(path_map)
    path_map.each do |name, paths|
      map[name.to_s] = Array(paths).map{ |path| Valid.path!(path) }
    end
    map
end

#platform=(value) ⇒ Object

Alternate singular form of #platforms.



801
802
803
# File 'lib/indexer/metadata.rb', line 801

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

#platforms=(value) ⇒ Object

Deprecated.

List of platforms supported.



352
353
354
355
356
357
358
# File 'lib/indexer/metadata.rb', line 352

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.



462
463
464
465
466
467
468
469
470
471
472
# File 'lib/indexer/metadata.rb', line 462

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



766
767
768
# File 'lib/indexer/metadata.rb', line 766

def require_paths
  load_path
end

#require_paths=(value) ⇒ Object

RubyGems term for #load_path.



773
774
775
# File 'lib/indexer/metadata.rb', line 773

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:



369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/indexer/metadata.rb', line 369

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.



780
781
782
# File 'lib/indexer/metadata.rb', line 780

def requires
  requirements
end

#requires=(value) ⇒ Object

Alternate short name for #requirements.



787
788
789
# File 'lib/indexer/metadata.rb', line 787

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.



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

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:



700
701
702
703
704
# File 'lib/indexer/metadata.rb', line 700

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.



886
887
888
889
# File 'lib/indexer/metadata.rb', line 886

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.



451
452
453
454
# File 'lib/indexer/metadata.rb', line 451

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.



814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
# File 'lib/indexer/metadata.rb', line 814

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 }

  customs.each do |name|
$stderr.puts self[name]
    h[name] = self[name]
  end

  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?



614
615
616
617
618
# File 'lib/indexer/metadata.rb', line 614

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

#version=(version) ⇒ Object

Sets the version of the project.

Parameters:

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.



503
504
505
506
# File 'lib/indexer/metadata.rb', line 503

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