class QB::Package::Version::Leveled

An attempt to unify NPM and Gem version schemes to a reasonable extend, and hopefully cover whatever else the cat may drag in.

Intended to be immutable for practical purposes.

Constants

DEV
LEVELS
RC
RELEASE

Public Class Methods

level_for(prerelease: [], build: [], **etc) click to toggle source

Get the level for version prop values. Returns `nil` if they are not “leveled”.

@param [Array<String | Integer>] prerelease:

The prerelease segments of the version.

@param [Array<String | Integer>] build:

The build segments of the version.

@param [Hash<Symbol, Object>] **etc

Really, anything, but meant to allow you to just pass all
{QB::Package::Version} prop values to the method.

@return [nil]

If the prop values don't have a level.

@return ['dev' | 'rc' | 'release']

If the values do have a level.
# File lib/qb/package/version/leveled.rb, line 78
def self.level_for prerelease: [], build: [], **etc
  return RELEASE if prerelease.empty?
  
  return DEV if prerelease[0] == DEV
  
  if  prerelease[0] == RC &&
      prerelease.length == 2 &&
      t.non_neg_int.test( prerelease[1] )
    return RC
  end
  
  nil
end
level_for!(**values) click to toggle source

Just like {.level_for} but raises if the props don't represent a valid level.

@param (see .level_for) @return (see .level_for)

@raise [ArgumentError]

If the prop values don't represent a version level.
# File lib/qb/package/version/leveled.rb, line 102
  def self.level_for! **values
    level_for( **values ).tap { |response|
      if response.nil?
        raise ArgumentError.new binding.erb <<-END
          Prop values not valid for a leveled version:
          
              <%= values.pretty_inspect %>
          
        END
      end
    }
  end
new(**values) click to toggle source

Construct a new Version

Calls superclass method QB::Util::Resource::new
# File lib/qb/package/version/leveled.rb, line 120
def initialize **values
  # Just to do the type check...
  self.class.level_for! **values
  super **values
end

Public Instance Methods

dev?() click to toggle source

@return [Boolean]

True if this version is a dev prerelease (first prerelease element
is 'dev').
# File lib/qb/package/version/leveled.rb, line 141
def dev?
  level == DEV
end
level() click to toggle source

Instance Methods

# File lib/qb/package/version/leveled.rb, line 130
def level
  self.class.level_for \
    prerelease: prerelease,
    build: build
end
rc?() click to toggle source

@return [Boolean]

True if this version is a release candidate (first prerelease element
is 'rc').
# File lib/qb/package/version/leveled.rb, line 150
def rc?
  level == RC
end
transition_to(level, **options) click to toggle source

@todo Document bump method.

@param [type] arg_name

@todo Add name param description.

@return [return_type]

@todo Document return value.
# File lib/qb/package/version/leveled.rb, line 283
def transition_to level, **options
  Types.level.check level.to_s
  
  method_name = "transition_to_#{ level }"
  if options.empty?
    public_send method_name
  else
    public_send method_name, **options
  end
end
transition_to_dev(inc: :patch) click to toggle source

@todo Document bump_dev method.

@param [type] arg_name

@todo Add name param description.

@return [return_type]

@todo Document return value.
# File lib/qb/package/version/leveled.rb, line 170
def transition_to_dev inc: :patch
  props = { prerelease: ['dev'] }
  
  t.match level,
    'release', ->(_) {
      succ = public_send( inc ).succ
      
      merge inc => succ, **props
    },
    
    'rc', ->(_) {
      merge **props
    },
    
    'dev',  ->(_) {
      raise QB::VersionError,
        "Version #{ self } is already at `dev` level"
    }
end
transition_to_rc(existing_versions: nil) click to toggle source

Transition to next release-candidate version.

This is a little tricky because we need to know what the last rc version was, which is not in the version in most cases.

@param [nil | String | Array] existing_versions:

Required when transitioning *from* `dev` level; ignored from `rc` and
`release` levels.

> When transitioning from `dev` to `rc` we need to know what `rc.X`
versions have already been used in order to figure out the correct
next one.

Value details:

-   `nil` - Default value; fine when {#level} is `release` or `rc`. An
    {ArgumentError} will be raised if {#level} is `dev`.

-   `String` -

@return [return_type]

@todo Document return value.
# File lib/qb/package/version/leveled.rb, line 214
  def transition_to_rc existing_versions: nil
    t.match level,
      'release', ->(_) {
        raise QB::VersionError,
          "Can not transition from `release` to `rc` levels (for #{ self })"
      },
      
      'rc', ->(_) {
        merge prerelease: ['rc', prerelease[1].succ]
      },
      
      'dev', ->(_) {
        if existing_versions.nil?
          raise ArgumentError.squished <<-END
            Can't bump to next rc version without knowing what rc versions have
            already been used.
          END
        elsif existing_versions.is_a? String
          existing_versions = self.class.extract existing_versions
        end
        
        last_existing_rc = existing_versions.
          select { |version|
            version.rc? && version.release == release
          }.
          sort.
          last
        
        rc_number = if last_existing_rc.nil?
          0
        else
          last_existing_rc.prerelease[1].succ
        end
        
        merge prerelease: ['rc', rc_number]
      }
  end
transition_to_release() click to toggle source

@todo Document transition_to_release method.

@return [QB::Package::Version]

# File lib/qb/package/version/leveled.rb, line 257
def transition_to_release
  t.match level,
    'release', ->(_) {
      raise QB::VersionError,
        "Version #{ self } is already at `release` level"
    },
    
    'dev', ->(_) {
      raise QB::VersionError,
        "Can not transition from `dev` to `release` levels (for #{ self })"
    },
    
    'rc', ->(_) {
      release_version
    }
end