semver2 3.1.2 → 3.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.semver CHANGED
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  :major: 3
3
- :minor: 1
3
+ :minor: 3
4
4
  :patch: 2
5
5
  :special: ''
6
+ :metadata: ''
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- SemVer2 3.1.x gem, following semver.org 2.0.0-rc.1
1
+ SemVer2 3.3.x gem, following semver.org 2.0.0-rc.2
2
2
  ======
3
3
 
4
4
  quickstart on the command line
@@ -9,10 +9,18 @@ install it
9
9
 
10
10
  use it
11
11
 
12
+ % semver # => v2.3.4
13
+ Find the .semver file and print a formatted string from this.
14
+
12
15
  % semver init
16
+ Initialize the .semver file.
17
+
13
18
  % semver tag # => v0.0.0
19
+ Print the tag for the current .semver file.
20
+
14
21
  % semver inc minor # => v0.1.0
15
- % semver special 'alpha.45' # => v0.1.0-alpha.45
22
+ % semver pre 'alpha.45' # => v0.1.0-alpha.45
23
+ % semver meta 'md5.abc123' # => v0.1.0-alpha.45+md5.abc123
16
24
  % semver format "%M.%m" # => 0.1
17
25
  % git tag -a `semver tag`
18
26
  % say 'that was easy'
@@ -25,14 +33,29 @@ quickstart for ruby
25
33
  v.major # => "0"
26
34
  v.major += 1
27
35
  v.major # => "1"
28
- v.special = 'alpha.46'
29
- v.format "%M.%m.%p%s" # => "1.1.0-alpha.46"
30
- v.to_s # => "v1.1.0"
36
+ v.prerelease = 'alpha.46'
37
+ v.metadata = 'md5.abc123'
38
+ v.format "%M.%m.%p%s%d" # => "1.1.0-alpha.46+md5.abc123"
39
+ v.to_s # => "v1.1.0-alpha.46+md5.abc123"
31
40
  v.save
32
41
 
42
+
33
43
  git integration
34
44
  ---------------
35
45
  % git config --global alias.semtag '!git tag -a $(semver tag) -m "tagging $(semver tag)"'
36
46
 
37
- [Franco Lazzarino](mailto:flazzarino@gmail.com)
38
- [Henrik Feldt](mailto:henrik@haf.se)
47
+
48
+ existing 'SemVer' class from other gem?
49
+ ---------------------------------------
50
+ You can now do this:
51
+
52
+ require 'xsemver'
53
+ v = XSemVer::SemVer.find
54
+ # ...
55
+ v.save
56
+
57
+ creds
58
+ -----
59
+ * [Franco Lazzarino](mailto:flazzarino@gmail.com)
60
+ * [Henrik Feldt](mailto:henrik@haf.se)
61
+ * [James Childress](mailto:james@childr.es)
data/bin/semver CHANGED
@@ -1,83 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'fileutils'
4
- require 'semver'
5
-
6
- class CommandError < StandardError; end
3
+ require 'runner'
7
4
 
8
5
  begin
9
- command = ARGV.shift || 'tag'
10
-
11
- case command
12
- when /^init(ialize)?$/
13
- file = SemVer::FILE_NAME
14
-
15
- if File.exist? file
16
- puts "#{file} already exists"
17
- else
18
- version = SemVer.new
19
- version.save file
20
- end
21
-
22
- when /^inc(rement)?$/
23
- version = SemVer.find
24
- dimension = ARGV.shift or raise CommandError, "required: major | minor | patch"
25
-
26
- case dimension
27
- when 'major'
28
- version.major += 1
29
- version.minor = 0
30
- version.patch = 0
31
-
32
- when 'minor'
33
- version.minor += 1
34
- version.patch = 0
35
-
36
- when 'patch'
37
- version.patch += 1
38
-
39
- else
40
- raise CommandError, "#{dimension} is invalid: major | minor | patch"
41
- end
42
-
43
- version.special = ''
44
- version.save
45
-
46
- when /^spe(cial)?$/
47
- version = SemVer.find
48
- special_str = ARGV.shift or raise CommandError, "required: an arbitrary string (beta, alfa, romeo, etc)"
49
- version.special = special_str
50
- version.save
51
-
52
- when 'format'
53
- version = SemVer.find
54
- format_str = ARGV.shift or raise CommandError, "required: format string"
55
- version.format format_str
56
-
57
- when 'tag'
58
- version = SemVer.find
59
- puts version.to_s
60
-
61
- when 'help'
62
- puts <<-HELP
63
- semver commands
64
- ---------------
65
-
66
- init[ialze] # initialize semantic version tracking
67
- inc[rement] major | minor | patch # increment a specific version number
68
- spe[cial] [STRING] # set a special version suffix
69
- format # printf like format: %M, %m, %p, %s
70
- tag # equivalent to format 'v%M.%m.%p%s'
71
- help
72
-
73
- PLEASE READ http://semver.org
74
- HELP
75
-
76
- else raise CommandError, "invalid command #{command}"
77
- end
78
-
79
- rescue CommandError => e
6
+ XSemVer::Runner.new *ARGV
7
+ rescue XSemVer::Runner::CommandError => e
80
8
  puts e.message
81
9
  puts "#{$0} help for more info"
82
10
  exit 1
83
- end
11
+ end
@@ -0,0 +1,68 @@
1
+ module XSemVer
2
+
3
+ # Represents the pre-release portion of a SemVer string.
4
+ class PreRelease
5
+
6
+ ONLY_DIGITS = /\A\d+\z/
7
+
8
+ attr_reader :ids
9
+
10
+ include Comparable
11
+
12
+
13
+
14
+
15
+ def initialize(prerelease_string)
16
+ @ids = prerelease_string.split(".")
17
+ end
18
+
19
+ def to_s
20
+ ids.join "."
21
+ end
22
+
23
+ def empty?
24
+ ids.empty?
25
+ end
26
+
27
+
28
+
29
+
30
+ # The SemVer 2.0.0-rc2 spec uses this example for determining pre-release precedence:
31
+ # 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.
32
+ # Pre-release precedence is calculated using the following rules, which are listed above their corresponding code.
33
+ def <=>(other)
34
+
35
+ # A SemVer with no prerelease data is 'greater' than a SemVer with any prerelease data.
36
+ # If both prereleases are empty, they are equal.
37
+ return 1 if empty? && !other.empty?
38
+ return -1 if !empty? && other.empty?
39
+ return 0 if empty? && other.empty?
40
+
41
+ [ids.size, other.ids.size].max.times do |n|
42
+ id = ids[n]
43
+ oid = other.ids[n]
44
+
45
+ # A pre-release with fewer ids is less than a pre-release with more ids. (1.0.0-alpha < 1.0.0-alpha.1)
46
+ return 1 if oid.nil?
47
+ return -1 if id.nil?
48
+
49
+ # If a pre-release id consists of only numbers, it is compared numerically.
50
+ if id =~ ONLY_DIGITS && oid =~ ONLY_DIGITS
51
+ id = id.to_i
52
+ oid = oid.to_i
53
+ end
54
+
55
+ # If a pre-release id contains one or more letters, it is compared alphabetically.
56
+ comparison = (id <=> oid)
57
+ return comparison unless comparison == 0
58
+ end
59
+
60
+ 0
61
+ end
62
+
63
+
64
+
65
+
66
+ end
67
+
68
+ end
data/lib/runner.rb ADDED
@@ -0,0 +1,127 @@
1
+ require 'semver'
2
+
3
+ module XSemVer
4
+
5
+ # Contains the logic for performing SemVer operations from the command line.
6
+ class Runner
7
+
8
+ class CommandError < StandardError
9
+ end
10
+
11
+
12
+ # Run a semver command. Raise a CommandError if the command does not exist.
13
+ # Expects an array of commands, such as ARGV.
14
+ def initialize(*args)
15
+ @args = args
16
+ command = @args.shift || :tag
17
+ method = "run_#{command}"
18
+ raise CommandError, "invalid command #{command}" unless self.class.method_defined?(method)
19
+ send method
20
+ end
21
+
22
+
23
+ # Return the text to be displayed when the 'help' command is run.
24
+ def self.help_text
25
+ <<-HELP
26
+ semver commands
27
+ ---------------
28
+
29
+ init[ialze] # initialize semantic version tracking
30
+ inc[rement] major | minor | patch # increment a specific version number
31
+ pre[release] [STRING] # set a pre-release version suffix
32
+ spe[cial] [STRING] # set a pre-release version suffix (deprecated)
33
+ meta[data] [STRING] # set a metadata version suffix
34
+ format # printf like format: %M, %m, %p, %s
35
+ tag # equivalent to format 'v%M.%m.%p%s'
36
+ help
37
+
38
+ PLEASE READ http://semver.org
39
+ HELP
40
+ end
41
+
42
+
43
+ # Create a new .semver file if the file does not exist.
44
+ def run_initialize
45
+ file = SemVer.file_name
46
+ if File.exist? file
47
+ puts "#{file} already exists"
48
+ else
49
+ version = SemVer.new
50
+ version.save file
51
+ end
52
+ end
53
+ alias :run_init :run_initialize
54
+
55
+
56
+ # Increment the major, minor, or patch of the .semver file.
57
+ def run_increment
58
+ version = SemVer.find
59
+ dimension = @args.shift or raise CommandError, "required: major | minor | patch"
60
+ case dimension
61
+ when 'major'
62
+ version.major += 1
63
+ version.minor = 0
64
+ version.patch = 0
65
+ when 'minor'
66
+ version.minor += 1
67
+ version.patch = 0
68
+ when 'patch'
69
+ version.patch += 1
70
+ else
71
+ raise CommandError, "#{dimension} is invalid: major | minor | patch"
72
+ end
73
+ version.special = ''
74
+ version.metadata = ''
75
+ version.save
76
+ end
77
+ alias :run_inc :run_increment
78
+
79
+
80
+ # Set the pre-release of the .semver file.
81
+ def run_special
82
+ version = SemVer.find
83
+ special_str = @args.shift or raise CommandError, "required: an arbitrary string (beta, alfa, romeo, etc)"
84
+ version.special = special_str
85
+ version.save
86
+ end
87
+ alias :run_spe :run_special
88
+ alias :run_pre :run_special
89
+ alias :run_prerelease :run_special
90
+
91
+
92
+ # Set the metadata of the .semver file.
93
+ def run_metadata
94
+ version = SemVer.find
95
+ special_str = @args.shift or raise CommandError, "required: an arbitrary string (beta, alfa, romeo, etc)"
96
+ version.metadata = special_str
97
+ version.save
98
+ end
99
+ alias :run_meta :run_metadata
100
+
101
+
102
+ # Output the semver as specified by a format string.
103
+ # See: SemVer#format
104
+ def run_format
105
+ version = SemVer.find
106
+ format_str = @args.shift or raise CommandError, "required: format string"
107
+ puts version.format(format_str)
108
+ end
109
+
110
+
111
+ # Output the semver with the default formatting.
112
+ # See: SemVer#to_s
113
+ def run_tag
114
+ version = SemVer.find
115
+ puts version.to_s
116
+ end
117
+
118
+
119
+ # Output instructions for using the semvar command.
120
+ def run_help
121
+ puts self.class.help_text
122
+ end
123
+
124
+
125
+ end
126
+
127
+ end
data/lib/xsemver.rb CHANGED
@@ -1,12 +1,17 @@
1
1
  require 'yaml'
2
2
  require 'semver/semvermissingerror'
3
+ require 'pre_release'
3
4
 
4
5
  module XSemVer
5
6
  # sometimes a library that you are using has already put the class
6
7
  # 'SemVer' in global scope. Too Bad®. Use this symbol instead.
7
8
  class SemVer
8
9
  FILE_NAME = '.semver'
9
- TAG_FORMAT = 'v%M.%m.%p%s'
10
+ TAG_FORMAT = 'v%M.%m.%p%s%d'
11
+
12
+ def SemVer.file_name
13
+ FILE_NAME
14
+ end
10
15
 
11
16
  def SemVer.find dir=nil
12
17
  v = SemVer.new
@@ -18,13 +23,13 @@ module XSemVer
18
23
  def SemVer.find_file dir=nil
19
24
  dir ||= Dir.pwd
20
25
  raise "#{dir} is not a directory" unless File.directory? dir
21
- path = File.join dir, FILE_NAME
26
+ path = File.join dir, file_name
22
27
 
23
28
  Dir.chdir dir do
24
29
  while !File.exists? path do
25
30
  raise SemVerMissingError, "#{dir} is not semantic versioned", caller if File.dirname(path).match(/(\w:\/|\/)$/i)
26
31
  path = File.join File.dirname(path), ".."
27
- path = File.expand_path File.join(path, FILE_NAME)
32
+ path = File.expand_path File.join(path, file_name)
28
33
  puts "semver: looking at #{path}"
29
34
  end
30
35
  return path
@@ -32,9 +37,9 @@ module XSemVer
32
37
 
33
38
  end
34
39
 
35
- attr_accessor :major, :minor, :patch, :special
40
+ attr_accessor :major, :minor, :patch, :special, :metadata
36
41
 
37
- def initialize major=0, minor=0, patch=0, special=''
42
+ def initialize major=0, minor=0, patch=0, special='', metadata=''
38
43
  major.kind_of? Integer or raise "invalid major: #{major}"
39
44
  minor.kind_of? Integer or raise "invalid minor: #{minor}"
40
45
  patch.kind_of? Integer or raise "invalid patch: #{patch}"
@@ -43,7 +48,11 @@ module XSemVer
43
48
  special =~ /[A-Za-z][0-9A-Za-z\.]+/ or raise "invalid special: #{special}"
44
49
  end
45
50
 
46
- @major, @minor, @patch, @special = major, minor, patch, special
51
+ unless metadata.empty?
52
+ metadata =~ /\A[A-Za-z0-9][0-9A-Za-z\.-]*\z/ or raise "invalid metadata: #{metadata}"
53
+ end
54
+
55
+ @major, @minor, @patch, @special, @metadata = major, minor, patch, special, metadata
47
56
  end
48
57
 
49
58
  def load file
@@ -52,7 +61,8 @@ module XSemVer
52
61
  @major = hash[:major] or raise "invalid semver file: #{file}"
53
62
  @minor = hash[:minor] or raise "invalid semver file: #{file}"
54
63
  @patch = hash[:patch] or raise "invalid semver file: #{file}"
55
- @special = hash[:special] or raise "invalid semver file: #{file}"
64
+ @special = hash[:special] or raise "invalid semver file: #{file}"
65
+ @metadata = hash[:metadata] || ""
56
66
  end
57
67
 
58
68
  def save file=nil
@@ -62,7 +72,8 @@ module XSemVer
62
72
  :major => @major,
63
73
  :minor => @minor,
64
74
  :patch => @patch,
65
- :special => @special
75
+ :special => @special,
76
+ :metadata => @metadata
66
77
  }
67
78
 
68
79
  yaml = YAML.dump hash
@@ -73,11 +84,8 @@ module XSemVer
73
84
  fmt = fmt.gsub '%M', @major.to_s
74
85
  fmt = fmt.gsub '%m', @minor.to_s
75
86
  fmt = fmt.gsub '%p', @patch.to_s
76
- if @special.nil? or @special.length == 0 then
77
- fmt = fmt.gsub '%s', ''
78
- else
79
- fmt = fmt.gsub '%s', "-" + @special.to_s
80
- end
87
+ fmt = fmt.gsub('%s', prerelease? ? "-#{@special}" : '')
88
+ fmt = fmt.gsub('%d', metadata? ? "+#{@metadata}" : '')
81
89
  fmt
82
90
  end
83
91
 
@@ -85,20 +93,13 @@ module XSemVer
85
93
  format TAG_FORMAT
86
94
  end
87
95
 
96
+ # Compare version numbers according to SemVer 2.0.0-rc2
88
97
  def <=> other
89
- maj = major.to_i <=> other.major.to_i
90
- return maj unless maj == 0
91
-
92
- min = minor.to_i <=> other.minor.to_i
93
- return min unless min == 0
94
-
95
- pat = patch.to_i <=> other.patch.to_i
96
- return pat unless pat == 0
97
-
98
- spe = special <=> other.special
99
- return spec unless spe == 0
100
-
101
- 0
98
+ [:major, :minor, :patch].each do |method|
99
+ comparison = (send(method) <=> other.send(method))
100
+ return comparison unless comparison == 0
101
+ end
102
+ PreRelease.new(prerelease) <=> PreRelease.new(other.prerelease)
102
103
  end
103
104
 
104
105
  include Comparable
@@ -109,35 +110,63 @@ module XSemVer
109
110
  regex_str = Regexp.escape format
110
111
 
111
112
  # Convert all the format characters to named capture groups
112
- regex_str = regex_str.gsub('%M', '(?<major>\d+)').
113
+ regex_str = regex_str.
114
+ gsub('%M', '(?<major>\d+)').
113
115
  gsub('%m', '(?<minor>\d+)').
114
116
  gsub('%p', '(?<patch>\d+)').
115
- gsub('%s', '(?:-(?<special>[A-Za-z][0-9A-Za-z\.]+))?')
117
+ gsub('%s', '(?:-(?<special>[A-Za-z][0-9A-Za-z\.]+))?').
118
+ gsub('%d', '(?:\x2B(?<metadata>[0-9A-Za-z][0-9A-Za-z\.]*))?')
116
119
 
117
120
  regex = Regexp.new(regex_str)
118
121
  match = regex.match version_string
119
122
 
120
123
  if match
121
- major = minor = patch = nil
122
- special = ''
123
-
124
- # Extract out the version parts
125
- major = match[:major].to_i if match.names.include? 'major'
126
- minor = match[:minor].to_i if match.names.include? 'minor'
127
- patch = match[:patch].to_i if match.names.include? 'patch'
128
- special = match[:special] || '' if match.names.include? 'special'
129
-
130
- # Failed parse if major, minor, or patch wasn't found
131
- # and allow_missing is false
132
- return nil if !allow_missing and [major, minor, patch].any? {|x| x.nil? }
133
-
134
- # Otherwise, allow them to default to zero
135
- major ||= 0
136
- minor ||= 0
137
- patch ||= 0
138
-
139
- SemVer.new major, minor, patch, special
124
+ major = minor = patch = nil
125
+ special = metadata = ''
126
+
127
+ # Extract out the version parts
128
+ major = match[:major].to_i if match.names.include? 'major'
129
+ minor = match[:minor].to_i if match.names.include? 'minor'
130
+ patch = match[:patch].to_i if match.names.include? 'patch'
131
+ special = match[:special] || '' if match.names.include? 'special'
132
+ metadata = match[:metadata] || '' if match.names.include? 'metadata'
133
+
134
+ # Failed parse if major, minor, or patch wasn't found
135
+ # and allow_missing is false
136
+ return nil if !allow_missing and [major, minor, patch].any? {|x| x.nil? }
137
+
138
+ # Otherwise, allow them to default to zero
139
+ major ||= 0
140
+ minor ||= 0
141
+ patch ||= 0
142
+
143
+ SemVer.new major, minor, patch, special, metadata
140
144
  end
141
145
  end
146
+
147
+ # SemVer specification 2.0.0-rc2 states that anything after the '-' character is prerelease data.
148
+ # To be consistent with the specification verbage, #prerelease returns the same value as #special.
149
+ # TODO: Deprecate #special in favor of #prerelease?
150
+ def prerelease
151
+ special
152
+ end
153
+
154
+ # SemVer specification 2.0.0-rc2 states that anything after the '-' character is prerelease data.
155
+ # To be consistent with the specification verbage, #prerelease= sets the same value as #special.
156
+ # TODO: Deprecate #special= in favor of #prerelease=?
157
+ def prerelease=(pre)
158
+ self.special = pre
159
+ end
160
+
161
+ # Return true if the SemVer has a non-empty #prerelease value. Otherwise, false.
162
+ def prerelease?
163
+ !special.nil? && special.length > 0
164
+ end
165
+
166
+ # Return true if the SemVer has a non-empty #metadata value. Otherwise, false.
167
+ def metadata?
168
+ !metadata.nil? && metadata.length > 0
169
+ end
170
+
142
171
  end
143
172
  end
data/semver2.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.summary = "Semantic Versioning"
8
8
  spec.description = "maintain versions as per http://semver.org"
9
9
  spec.email = "henrik@haf.se"
10
- spec.authors = ["Francesco Lazzarino", "Henrik Feldt"]
10
+ spec.authors = ["Francesco Lazzarino", "Henrik Feldt", "James Childress"]
11
11
  spec.homepage = 'https://github.com/haf/semver'
12
12
  spec.executables << 'semver'
13
13
  spec.files = [".semver", "semver2.gemspec", "README.md"] + Dir["lib/**/*.rb"] + Dir['bin/*']
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semver2
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2
4
+ version: 3.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Francesco Lazzarino
9
9
  - Henrik Feldt
10
+ - James Childress
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2013-02-05 00:00:00.000000000 Z
14
+ date: 2013-06-23 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: rspec
@@ -38,6 +39,8 @@ files:
38
39
  - .semver
39
40
  - semver2.gemspec
40
41
  - README.md
42
+ - lib/pre_release.rb
43
+ - lib/runner.rb
41
44
  - lib/semver/semvermissingerror.rb
42
45
  - lib/semver.rb
43
46
  - lib/xsemver.rb