├── .gitignore ├── .rubocop.yml ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── lib ├── liferaft.rb └── liferaft │ ├── gem_version.rb │ └── version.rb ├── liferaft.gemspec └── spec ├── comparison_spec.rb ├── spec_helper.rb └── version_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | Lint/Void: 2 | Enabled: false 3 | 4 | Metrics/AbcSize: 5 | Max: 27 6 | 7 | Metrics/CyclomaticComplexity: 8 | Max: 7 9 | 10 | Metrics/LineLength: 11 | Max: 100 12 | 13 | Style/Documentation: 14 | Enabled: false 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.3.1 4 | - 2.0.0-p598 5 | cache: bundler 6 | script: 7 | - bundle exec rake spec 8 | - bundle exec rubocop 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | group :development do 6 | gem 'bacon' 7 | gem 'mocha-on-bacon' 8 | gem 'mocha', '~> 0.11.4' 9 | gem 'prettybacon', git: 'https://github.com/irrationalfab/PrettyBacon.git', branch: 'master' 10 | gem 'coveralls', require: false 11 | gem 'rubocop', require: false 12 | end 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Boris Bügling 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Liferaft 2 | 3 | [![Build Status](http://img.shields.io/travis/neonichu/liferaft/master.svg?style=flat)](https://travis-ci.org/neonichu/liferaft) 4 | [![Coverage Status](https://coveralls.io/repos/neonichu/liferaft/badge.svg)](https://coveralls.io/r/neonichu/liferaft) 5 | [![Gem Version](http://img.shields.io/gem/v/liferaft.svg?style=flat)](http://badge.fury.io/rb/liferaft) 6 | [![Code Climate](http://img.shields.io/codeclimate/github/neonichu/liferaft.svg?style=flat)](https://codeclimate.com/github/neonichu/liferaft) 7 | 8 | Liferaft parses Apple build numbers, like `6D1002`. 9 | 10 | ## Usage 11 | 12 | ```ruby 13 | v = Version.new('6D1002') 14 | 15 | puts "#{v.major}.#{v.minor}.#{v.patch} Build #{v.build}" 16 | ## => '6.3.1 Build 2' 17 | ``` 18 | 19 | ## Installation 20 | 21 | Add this line to your application's Gemfile: 22 | 23 | ```ruby 24 | gem 'liferaft' 25 | ``` 26 | 27 | And then execute: 28 | 29 | $ bundle 30 | 31 | Or install it yourself as: 32 | 33 | $ gem install liferaft 34 | 35 | ## Contributing 36 | 37 | 1. Fork it ( https://github.com/neonichu/liferaft/fork ) 38 | 2. Create your feature branch (`git checkout -b my-new-feature`) 39 | 3. Commit your changes (`git commit -am 'Add some feature'`) 40 | 4. Push to the branch (`git push origin my-new-feature`) 41 | 5. Create a new Pull Request 42 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | 3 | def specs(dir) 4 | list = FileList["spec/#{dir}/*_spec.rb"] 5 | list.sample(list.count).join(' ') 6 | end 7 | 8 | desc 'Runs all the specs' 9 | task :spec do 10 | sh "bundle exec bacon #{specs('**')}" 11 | end 12 | 13 | task default: :spec 14 | -------------------------------------------------------------------------------- /lib/liferaft.rb: -------------------------------------------------------------------------------- 1 | require 'liferaft/gem_version' 2 | require 'liferaft/version' 3 | -------------------------------------------------------------------------------- /lib/liferaft/gem_version.rb: -------------------------------------------------------------------------------- 1 | module Liferaft 2 | VERSION = '0.0.6'.freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/liferaft/version.rb: -------------------------------------------------------------------------------- 1 | module Liferaft 2 | def self.version_string_create(major, minor, patch, build = 0) 3 | "#{major}#{(minor + 'A'.ord).chr}#{patch * 1000 + build}" 4 | end 5 | 6 | class Version 7 | include Comparable 8 | 9 | attr_reader :major, :minor, :patch, :build 10 | 11 | def initialize(version_string) 12 | components = version_string.downcase.split(/[a-z]/) 13 | character = version_string.downcase.gsub(/[^a-z]/, '') 14 | 15 | if character.length > 2 || character.empty? 16 | @major = @minor = @patch = @build = 0 17 | return 18 | end 19 | 20 | @major = components[0].to_i 21 | @minor = character.ord - 'a'.ord 22 | @patch = components[1].to_i / 1000 23 | @build = (character.length == 2 ? character[-1].ord : 0) + components[1].to_i % 1000 24 | end 25 | 26 | def to_s 27 | "#{@major}.#{@minor}.#{@patch} Build #{@build}" 28 | end 29 | 30 | def <=>(other) 31 | %i(major minor patch build).lazy.map do |component| 32 | send(component) <=> other.send(component) 33 | end.find(&:nonzero?) || 0 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /liferaft.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'liferaft/gem_version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'liferaft' 8 | spec.version = Liferaft::VERSION 9 | spec.authors = ['Boris Bügling'] 10 | spec.email = ['boris@icculus.org'] 11 | spec.summary = 'Liferaft parses Apple build numbers, like 6D1002' 12 | spec.homepage = 'https://github.com/segiddins/liferaft' 13 | spec.license = 'MIT' 14 | 15 | spec.files = `git ls-files -z`.split("\x0") 16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 17 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 18 | spec.require_paths = ['lib'] 19 | 20 | spec.add_development_dependency 'bundler', '~> 1.7' 21 | spec.add_development_dependency 'rake', '~> 10.0' 22 | end 23 | -------------------------------------------------------------------------------- /spec/comparison_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | module Liferaft 4 | describe Version do 5 | it 'compares 6D570 and 6D1002 correctly' do 6 | v1 = Version.new('6D570') 7 | v2 = Version.new('6D1002') 8 | 9 | v1.should < v2 10 | v2.should > v1 11 | end 12 | 13 | it 'implements the equality operator' do 14 | v1 = Version.new('6D570') 15 | v2 = Version.new('6D570') 16 | 17 | v1.should == v2 18 | end 19 | 20 | it 'implements greater-than-or-equals operator' do 21 | v1 = Version.new('6D570') 22 | v2 = Version.new('6D570') 23 | v3 = Version.new('6D002') 24 | 25 | v2.should >= v1 26 | v2.should >= v3 27 | end 28 | 29 | it 'implements less-than-or-equals operator' do 30 | v1 = Version.new('6D570') 31 | v2 = Version.new('6D570') 32 | v3 = Version.new('6D1002') 33 | 34 | v1.should <= v2 35 | v1.should <= v3 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'coveralls' 2 | Coveralls.wear! 3 | 4 | require 'pathname' 5 | ROOT = Pathname.new(File.expand_path('../../', __FILE__)) 6 | $LOAD_PATH.unshift((ROOT + 'lib').to_s) 7 | $LOAD_PATH.unshift((ROOT + 'spec').to_s) 8 | 9 | require 'bundler/setup' 10 | require 'bacon' 11 | require 'mocha-on-bacon' 12 | require 'pretty_bacon' 13 | 14 | require 'liferaft' 15 | -------------------------------------------------------------------------------- /spec/version_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | module Liferaft 4 | describe Liferaft do 5 | it 'writes 6D570 correctly' do 6 | version_string = Liferaft.version_string_create(6, 3, 0, 570) 7 | 8 | version_string.should == '6D570' 9 | end 10 | 11 | it 'writes 6D1002 correctly' do 12 | version_string = Liferaft.version_string_create(6, 3, 1, 2) 13 | 14 | version_string.should == '6D1002' 15 | end 16 | end 17 | 18 | describe Version do 19 | it 'parses 6E7 correctly' do 20 | version = Version.new('6E7') 21 | 22 | version.major.should == 6 23 | version.minor.should == 4 24 | version.patch.should == 0 25 | version.build.should == 7 26 | end 27 | 28 | it 'parses 6C131e correctly' do 29 | version = Version.new('6C131e') 30 | 31 | version.major.should == 6 32 | version.minor.should == 2 33 | version.patch.should == 0 34 | version.build.should == 232 35 | end 36 | 37 | it 'parses 6D570 correctly' do 38 | version = Version.new('6D570') 39 | 40 | version.major.should == 6 41 | version.minor.should == 3 42 | version.patch.should == 0 43 | version.build.should == 570 44 | end 45 | 46 | it 'parses 6D1002 correctly' do 47 | version = Version.new('6D1002') 48 | 49 | version.major.should == 6 50 | version.minor.should == 3 51 | version.patch.should == 1 52 | version.build.should == 0o02 53 | end 54 | 55 | it 'parses 6E7 correctly' do 56 | version = Version.new('6E7') 57 | 58 | version.major.should == 6 59 | version.minor.should == 4 60 | version.patch.should == 0 61 | version.build.should == 7 62 | end 63 | 64 | it 'parses 6E14 correctly' do 65 | version = Version.new('6E14') 66 | 67 | version.major.should == 6 68 | version.minor.should == 4 69 | version.patch.should == 0 70 | version.build.should == 14 71 | end 72 | 73 | it 'parses 6E14 correctly' do 74 | version = Version.new('6E14') 75 | 76 | version.major.should == 6 77 | version.minor.should == 4 78 | version.patch.should == 0 79 | version.build.should == 14 80 | end 81 | 82 | it 'parses 16E14 correctly' do 83 | version = Version.new('16E14') 84 | 85 | version.major.should == 16 86 | version.minor.should == 4 87 | version.patch.should == 0 88 | version.build.should == 14 89 | end 90 | 91 | it 'parses 7A121l correctly' do 92 | version = Version.new('7A121l') 93 | 94 | version.major.should == 7 95 | version.minor.should == 0 96 | version.patch.should == 0 97 | version.build.should == 229 98 | end 99 | 100 | it 'is resilient against empty minor versions' do 101 | version = Version.new('614') 102 | 103 | version.major.should == 0 104 | version.minor.should == 0 105 | version.patch.should == 0 106 | version.build.should == 0 107 | end 108 | 109 | it 'is resilient against multi-character minor versions' do 110 | version = Version.new('6EEE14') 111 | 112 | version.major.should == 0 113 | version.minor.should == 0 114 | version.patch.should == 0 115 | version.build.should == 0 116 | end 117 | 118 | it 'is resilient against parsing broken versions' do 119 | version = Version.new('ERTTR456E') 120 | 121 | version.major.should == 0 122 | version.minor.should == 0 123 | version.patch.should == 0 124 | version.build.should == 0 125 | end 126 | 127 | it 'can convert a Version object to string' do 128 | version = Version.new('6E14') 129 | 130 | version.to_s.should == '6.4.0 Build 14' 131 | end 132 | end 133 | end 134 | --------------------------------------------------------------------------------