cliver 0.1.2 → 0.1.3
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/.travis.yml +1 -1
- data/cliver.gemspec +1 -0
- data/lib/cliver.rb +25 -2
- data/lib/cliver/assertion.rb +13 -15
- data/lib/cliver/detector.rb +14 -11
- data/lib/cliver/detector/default.rb +15 -2
- data/lib/cliver/version.rb +2 -1
- data/lib/cliver/which/posix.rb +1 -0
- data/lib/cliver/which/windows.rb +2 -1
- data/spec/cliver_spec.rb +25 -0
- metadata +3 -3
data/.travis.yml
CHANGED
data/cliver.gemspec
CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
19
19
|
spec.require_paths = ['lib']
|
20
|
+
spec.has_rdoc = 'yard'
|
20
21
|
|
21
22
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
23
|
spec.add_development_dependency 'rake'
|
data/lib/cliver.rb
CHANGED
@@ -5,9 +5,32 @@ require 'cliver/assertion'
|
|
5
5
|
require 'cliver/detector'
|
6
6
|
require 'cliver/detector/default'
|
7
7
|
|
8
|
+
# Cliver is tool for making dependency assertions against
|
9
|
+
# command-line executables.
|
8
10
|
module Cliver
|
9
|
-
#
|
11
|
+
# @see Cliver::Assertion
|
12
|
+
# @overload (see Cliver::Assertion#initialize)
|
13
|
+
# @param (see Cliver::Assertion#initialize)
|
14
|
+
# @raise (see Cliver::Assertion#assert!)
|
15
|
+
# @return (see Cliver::Assertion#assert!)
|
10
16
|
def self.assert(*args, &block)
|
11
|
-
Assertion.
|
17
|
+
Assertion.new(*args, &block).assert!
|
18
|
+
end
|
19
|
+
|
20
|
+
extend self
|
21
|
+
|
22
|
+
# Wraps Cliver::assert and returns truthy/false instead of raising
|
23
|
+
# @see Cliver::assert
|
24
|
+
# @overload (see Cliver::Assertion#initialize)
|
25
|
+
# @param (see Cliver::Assertion#initialize)
|
26
|
+
# @return [False,String] either returns false or the reason why the
|
27
|
+
# assertion was unmet.
|
28
|
+
def dependency_unmet?(*args, &block)
|
29
|
+
Cliver.assert(*args, &block)
|
30
|
+
false
|
31
|
+
rescue Assertion::DependencyNotMet => error
|
32
|
+
# Cliver::Assertion::VersionMismatch -> 'Version Mismatch'
|
33
|
+
reason = error.class.name.split('::').last.gsub(/(?<!\A)[A-Z]/, ' \\0')
|
34
|
+
"#{reason}: #{error.message}"
|
12
35
|
end
|
13
36
|
end
|
data/lib/cliver/assertion.rb
CHANGED
@@ -9,17 +9,14 @@ module Cliver
|
|
9
9
|
|
10
10
|
include Which # platform-specific implementation of `which`
|
11
11
|
|
12
|
+
# An exception class raised when assertion is not met
|
12
13
|
DependencyNotMet = Class.new(ArgumentError)
|
13
|
-
DependencyVersionMismatch = Class.new(DependencyNotMet)
|
14
|
-
DependencyNotFound = Class.new(DependencyNotMet)
|
15
14
|
|
16
|
-
|
15
|
+
# An exception that is raised when executable present is the wrong version
|
16
|
+
DependencyVersionMismatch = Class.new(DependencyNotMet)
|
17
17
|
|
18
|
-
#
|
19
|
-
|
20
|
-
def self.assert!(*args, &block)
|
21
|
-
new(*args, &block).assert!
|
22
|
-
end
|
18
|
+
# An exception that is raised when executable is not present
|
19
|
+
DependencyNotFound = Class.new(DependencyNotMet)
|
23
20
|
|
24
21
|
# @overload initialize(executable, *requirements, options = {})
|
25
22
|
# @param executable [String]
|
@@ -29,15 +26,13 @@ module Cliver
|
|
29
26
|
# Where <operator> is optional (default '='') and in the set
|
30
27
|
# '=', '!=', '>', '<', '>=', '<=', or '~>'
|
31
28
|
# And <version> is dot-separated integers with optional
|
32
|
-
# alphanumeric pre-release suffix
|
33
|
-
#
|
29
|
+
# alphanumeric pre-release suffix. See also
|
30
|
+
# {http://docs.rubygems.org/read/chapter/16 Specifying Versions}
|
34
31
|
# @param options [Hash<Symbol,Object>]
|
35
|
-
# @
|
32
|
+
# @option options [Cliver::Detector, #to_proc] :detector
|
36
33
|
# @yieldparam [String] full path to executable
|
37
34
|
# @yieldreturn [String] Gem::Version-parsable string version
|
38
35
|
def initialize(executable, *args, &detector)
|
39
|
-
raise ArgumentError, 'executable' unless executable[EXECUTABLE_PATTERN]
|
40
|
-
|
41
36
|
options = args.last.kind_of?(Hash) ? args.pop : {}
|
42
37
|
|
43
38
|
@executable = executable.dup.freeze
|
@@ -49,14 +44,17 @@ module Cliver
|
|
49
44
|
# @raise [DependencyNotFound] if no installed version on your path
|
50
45
|
def assert!
|
51
46
|
version = installed_version
|
52
|
-
raise(DependencyNotFound, "#{@executable} missing.") unless version
|
47
|
+
raise(DependencyNotFound, "'#{@executable}' missing.") unless version
|
53
48
|
|
54
49
|
if @requirement && !@requirement.satisfied_by?(Gem::Version.new(version))
|
55
50
|
raise DependencyVersionMismatch,
|
56
|
-
"expected #{@executable} to be #{@requirement}, got #{version}"
|
51
|
+
"expected '#{@executable}' to be #{@requirement}, got #{version}"
|
57
52
|
end
|
58
53
|
end
|
59
54
|
|
55
|
+
# Finds the executable on your path using {Cliver::Which};
|
56
|
+
# if the executable is present and version requirements are specified,
|
57
|
+
# uses the specified detector to get the current version.
|
60
58
|
# @private
|
61
59
|
# @return [nil] if no version present
|
62
60
|
# @return [String] Gem::Version-parsable string version
|
data/lib/cliver/detector.rb
CHANGED
@@ -6,15 +6,19 @@ module Cliver
|
|
6
6
|
# @see Cliver::Detector::Default for reference implementation
|
7
7
|
module Detector
|
8
8
|
# Forward to default implementation
|
9
|
+
# @see Cliver::Detector::Default
|
10
|
+
# @overload (see Cliver::Detector::Default#initialize)
|
11
|
+
# @param (see Cliver::Detector::Default#initialize)
|
12
|
+
# @raise (see Cliver::Detector::Default#initialize)
|
13
|
+
# @return (see Cliver::Detector::Default#initialize)
|
9
14
|
def self.new(*args, &block)
|
10
15
|
Default.new(*args, &block)
|
11
16
|
end
|
12
17
|
|
13
|
-
# @param
|
18
|
+
# @param executable_path [String] the executable to test
|
14
19
|
# @return [Array<String>]
|
15
|
-
def version_command(
|
16
|
-
raise NotImplementedError
|
17
|
-
super
|
20
|
+
def version_command(executable_path)
|
21
|
+
raise NotImplementedError
|
18
22
|
end
|
19
23
|
|
20
24
|
# @return [Regexp] - the pattern used against the output
|
@@ -25,19 +29,18 @@ module Cliver
|
|
25
29
|
super
|
26
30
|
end
|
27
31
|
|
28
|
-
# @param
|
32
|
+
# @param executable_path [String] - the path to the executable to test
|
29
33
|
# @return [String] - should be Gem::Version-parsable.
|
30
|
-
def detect_version(
|
31
|
-
|
32
|
-
escaped_command_parts = command_parts.map(&Shellwords.method(:escape))
|
33
|
-
output = `#{escaped_command_parts.join(' ')} 2>&1`
|
34
|
+
def detect_version(executable_path)
|
35
|
+
output = `#{version_command(executable_path).shelljoin} 2>&1`
|
34
36
|
ver = output.scan(version_pattern)
|
35
37
|
ver && ver.first
|
36
38
|
end
|
37
39
|
|
38
40
|
# This is the interface that any detector must have.
|
39
|
-
#
|
40
|
-
# @
|
41
|
+
# If not overridden, returns a proc that wraps #detect_version
|
42
|
+
# @see #detect_version
|
43
|
+
# @return [Proc] following method signature of {#detect_version}
|
41
44
|
def to_proc
|
42
45
|
method(:detect_version).to_proc
|
43
46
|
end
|
@@ -8,7 +8,11 @@ module Cliver
|
|
8
8
|
class Detector::Default < Struct.new(:command_arg, :version_pattern)
|
9
9
|
include Detector
|
10
10
|
|
11
|
+
# Default pattern to use when searching {#version_command} output
|
11
12
|
DEFAULT_VERSION_PATTERN = /(?<=version )[0-9][.0-9a-z]+/i.freeze
|
13
|
+
|
14
|
+
# Default command argument to use against the executable to get
|
15
|
+
# version output
|
12
16
|
DEFAULT_COMMAND_ARG = '--version'.freeze
|
13
17
|
|
14
18
|
# Forgiving input, allows either argument if only one supplied.
|
@@ -24,16 +28,25 @@ module Cliver
|
|
24
28
|
super(command_arg, version_pattern)
|
25
29
|
end
|
26
30
|
|
31
|
+
# The pattern to match the version in {#version_command}'s output.
|
32
|
+
# Defaults to {DEFAULT_VERSION_PATTERN}
|
33
|
+
# @overload (see Cliver::Detector#version_pattern)
|
34
|
+
# @return (see Cliver::Detector#version_pattern)
|
27
35
|
def version_pattern
|
28
36
|
super || DEFAULT_VERSION_PATTERN
|
29
37
|
end
|
30
38
|
|
39
|
+
# The argument to pass to the executable to get current version
|
40
|
+
# Defaults to {DEFAULT_COMMAND_ARG}
|
41
|
+
# @return [String]
|
31
42
|
def command_arg
|
32
43
|
super || DEFAULT_COMMAND_ARG
|
33
44
|
end
|
34
45
|
|
35
|
-
|
36
|
-
|
46
|
+
# @overload (see Cliver::Detector#version_command)
|
47
|
+
# @return (see Cliver::Detector#version_command)
|
48
|
+
def version_command(executable_path)
|
49
|
+
[executable_path, command_arg]
|
37
50
|
end
|
38
51
|
end
|
39
52
|
end
|
data/lib/cliver/version.rb
CHANGED
data/lib/cliver/which/posix.rb
CHANGED
data/lib/cliver/which/windows.rb
CHANGED
@@ -6,13 +6,14 @@ module Cliver
|
|
6
6
|
# Windows-specific implementation of Which
|
7
7
|
# Required and mixed into Cliver::Which in windows environments
|
8
8
|
module Windows
|
9
|
+
# Windows-specific implementation of `which`
|
9
10
|
# @param executable [String]
|
10
11
|
# @return [nil,String] - path to found executable
|
11
12
|
def which(executable)
|
12
13
|
# `where` returns newline-separated files found on path, but doesn't
|
13
14
|
# ensure that they are executable as commands.
|
14
15
|
where = `where #{Shellwords.escape executable} 2>&1`
|
15
|
-
where.
|
16
|
+
where.lines.map(&:chomp).find do |found|
|
16
17
|
next if found.empty?
|
17
18
|
File.executable?(found)
|
18
19
|
end
|
data/spec/cliver_spec.rb
CHANGED
@@ -3,4 +3,29 @@ require 'cliver'
|
|
3
3
|
|
4
4
|
describe Cliver do
|
5
5
|
it { should respond_to :assert }
|
6
|
+
|
7
|
+
it { should respond_to :dependency_unmet? }
|
8
|
+
context '#dependency_unmet?' do
|
9
|
+
let(:requirements) { [] }
|
10
|
+
let(:detector) { proc { } }
|
11
|
+
subject { Cliver.dependency_unmet?(executable, *requirements, &detector) }
|
12
|
+
context 'when dependency is met' do
|
13
|
+
let(:executable) { 'ruby' }
|
14
|
+
it { should be_false }
|
15
|
+
end
|
16
|
+
context 'when dependency is present, but wrong version' do
|
17
|
+
let(:executable) { 'ruby' }
|
18
|
+
let(:requirements) { ['~>0.1.0'] }
|
19
|
+
let(:detector) { proc { RUBY_VERSION.sub('p', '.') } }
|
20
|
+
it { should_not be_false }
|
21
|
+
it { should match 'Dependency Version Mismatch:' }
|
22
|
+
it { should match "expected 'ruby' to be #{requirements}" }
|
23
|
+
end
|
24
|
+
context 'when dependency is not present' do
|
25
|
+
let(:executable) { 'ruxxxby' }
|
26
|
+
it { should_not be_false }
|
27
|
+
it { should match 'Dependency Not Found:' }
|
28
|
+
it { should match "'#{executable}' missing" }
|
29
|
+
end
|
30
|
+
end
|
6
31
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cliver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -163,4 +163,4 @@ test_files:
|
|
163
163
|
- spec/cliver/assertion_spec.rb
|
164
164
|
- spec/cliver/detector_spec.rb
|
165
165
|
- spec/cliver_spec.rb
|
166
|
-
has_rdoc:
|
166
|
+
has_rdoc: yard
|