semver2 3.1.2 → 3.3.2

Sign up to get free protection for your applications and to get access to all the features.
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