command_mapper 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abc51ed8c1f7edf0484053eb62854a56b13dce9d5e3ea7b3373799c4b7a1d4fb
4
- data.tar.gz: 0e7945e79e57cb99a4448b4eafef1237e9cc5e06d4523e13efd68b2767106a2f
3
+ metadata.gz: 254468c58bbee95ac037609a4ddefc34c026240b4933a37038df1bade5b7487e
4
+ data.tar.gz: 1fe51a7d6ad09b0b51c753bee28632e70292bfa9e9938896e22183c0327f48ae
5
5
  SHA512:
6
- metadata.gz: ea9449f43ab086e941cc011dffd778cea4d356a2a9171aef5496e9a4593f62ca3ba68356d455cc510046ee926970c290c065b76bf445ba843a317f60c0fbbd31
7
- data.tar.gz: 5979c264d481d50be2fed8ca17a19cb59b4c522303ff4d5cdf14164195b9b27fd6589ebe5b8e0b06276494f5298c6898fb297a97a606ca10d5fb916dbe1d568d
6
+ metadata.gz: c1fc9b041fafa2d92300bcbf312e8b1d848450bd4691b6b0eea57fb401a8d20b8a73613328c69cc5d323e9b42313ecc2f3e66b8bcfff14454a8cdb5bd5db5467
7
+ data.tar.gz: 62fd74bd469bff9620c94a8c0710f6d309bb0611af7e58664fa7d04808ee40b14d3b076fb8143a6fdbd409a0fd35fb12682e535c30b41ed616200dc7be982bd2
data/ChangeLog.md CHANGED
@@ -1,3 +1,7 @@
1
+ ### 0.3.0 / 2022-11-11
2
+
3
+ * Added {CommandMapper::Types::Dec}.
4
+
1
5
  ### 0.2.1 / 2022-04-22
2
6
 
3
7
  * Properly validate in {CommandMapper::OptionValue#validate} when an option,
data/README.md CHANGED
@@ -10,8 +10,8 @@
10
10
 
11
11
  ## Description
12
12
 
13
- Command Mapper maps a command's options and arguments to Class attributes to
14
- allow safely and securely executing commands.
13
+ Command Mapper maps an external command's options and arguments to Class
14
+ attributes to allow safely and securely executing commands.
15
15
 
16
16
  ## Features
17
17
 
@@ -20,6 +20,7 @@ allow safely and securely executing commands.
20
20
  * Supports common option types:
21
21
  * [Str][CommandMapper::Types::Str]: string values
22
22
  * [Num][CommandMapper::Types::Num]: numeric values
23
+ * [Dec][CommandMapper::Types::Dec]: decimal values
23
24
  * [Hex][CommandMapper::Types::Hex]: hexadecimal values
24
25
  * [Map][CommandMapper::Types::Map]: maps Ruby values to other String values.
25
26
  * `Map::YesNo`: maps `true`/`false` to `yes`/`no`.
@@ -50,6 +51,7 @@ allow safely and securely executing commands.
50
51
 
51
52
  [CommandMapper::Types::Str]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Str
52
53
  [CommandMapper::Types::Num]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Num
54
+ [CommandMapper::Types::Dec]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Dec
53
55
  [CommandMapper::Types::Hex]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Hex
54
56
  [CommandMapper::Types::Map]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Map
55
57
  [CommandMapper::Types::Enum]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Enum
File without changes
data/gemspec.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  name: command_mapper
2
2
  summary: Safe and secure execution of commands.
3
3
  description:
4
- Command Mapper maps a command's arguments to Class attributes to allow safely
5
- and securely executing commands.
4
+ Command Mapper maps an external command's arguments to Class attributes to
5
+ allow safely and securely executing commands.
6
6
 
7
7
  license: MIT
8
8
  authors: Postmodern
@@ -0,0 +1,84 @@
1
+ require 'command_mapper/types/type'
2
+
3
+ module CommandMapper
4
+ module Types
5
+ #
6
+ # Represents a decimal value (ex: `1.5`).
7
+ #
8
+ # @since 0.3.0
9
+ #
10
+ class Dec < Type
11
+
12
+ # The optional range of acceptable decimal numbers.
13
+ #
14
+ # @return [Range<Float,Float>, nil]
15
+ #
16
+ # @api semipublic
17
+ attr_reader :range
18
+
19
+ #
20
+ # Initializes the decimal type.
21
+ #
22
+ # @param [Range<Float,Float>] range
23
+ # Specifies the range of acceptable numbers.
24
+ #
25
+ def initialize(range: nil)
26
+ @range = range
27
+ end
28
+
29
+ #
30
+ # Validates a value.
31
+ #
32
+ # @param [String, Numeric] value
33
+ # The given value to validate.
34
+ #
35
+ # @return [true, (false, String)]
36
+ # Returns true if the value is valid, or `false` and a validation error
37
+ # message if the value is not compatible.
38
+ #
39
+ # @api semipublic
40
+ #
41
+ def validate(value)
42
+ case value
43
+ when Float
44
+ # no-op
45
+ when String
46
+ unless value =~ /\A\d+(?:\.\d+)?\z/
47
+ return [false, "contains non-decimal characters (#{value.inspect})"]
48
+ end
49
+ else
50
+ unless value.respond_to?(:to_f)
51
+ return [false, "cannot be converted into a Float (#{value.inspect})"]
52
+ end
53
+ end
54
+
55
+ if @range
56
+ unless @range.include?(value.to_f)
57
+ return [false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
58
+ end
59
+ end
60
+
61
+ return true
62
+ end
63
+
64
+ #
65
+ # Formats a decimal value.
66
+ #
67
+ # @param [String, Float, #to_f] value
68
+ # The given value to format.
69
+ #
70
+ # @return [String]
71
+ # The formatted decimal value.
72
+ #
73
+ # @api semipublic
74
+ #
75
+ def format(value)
76
+ case value
77
+ when Float, String then value.to_s
78
+ else value.to_f.to_s
79
+ end
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -58,7 +58,7 @@ module CommandMapper
58
58
  # The default `validate` method for all types.
59
59
  #
60
60
  # @param [Object]
61
- # The given value to format.
61
+ # The given value to validate.
62
62
  #
63
63
  # @return [true, (false, String)]
64
64
  # Returns true if the value is valid, or `false` and a validation error
@@ -1,6 +1,7 @@
1
1
  require 'command_mapper/types/type'
2
2
  require 'command_mapper/types/str'
3
3
  require 'command_mapper/types/num'
4
+ require 'command_mapper/types/dec'
4
5
  require 'command_mapper/types/hex'
5
6
  require 'command_mapper/types/map'
6
7
  require 'command_mapper/types/enum'
@@ -1,4 +1,4 @@
1
1
  module CommandMapper
2
2
  # Version of command_mapper
3
- VERSION = '0.2.1'
3
+ VERSION = '0.3.0'
4
4
  end
data/spec/commnad_spec.rb CHANGED
@@ -808,7 +808,7 @@ describe CommandMapper::Command do
808
808
  end
809
809
 
810
810
  it "must initialize a new command with the Hash of params and call #run_command" do
811
- if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
811
+ if RUBY_VERSION < '3.'
812
812
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
813
813
  else
814
814
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -846,7 +846,7 @@ describe CommandMapper::Command do
846
846
  end
847
847
 
848
848
  it "must initialize a new command with the Hash of params and call #spawn_command" do
849
- if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
849
+ if RUBY_VERSION < '3.'
850
850
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
851
851
  else
852
852
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -884,7 +884,7 @@ describe CommandMapper::Command do
884
884
  end
885
885
 
886
886
  it "must initialize a new command with the Hash of params and call #capture_command" do
887
- if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
887
+ if RUBY_VERSION < '3.'
888
888
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
889
889
  else
890
890
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -922,7 +922,7 @@ describe CommandMapper::Command do
922
922
  end
923
923
 
924
924
  it "must initialize a new command with the Hash of params and call #popen_command" do
925
- if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
925
+ if RUBY_VERSION < '3.'
926
926
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
927
927
  else
928
928
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -960,7 +960,7 @@ describe CommandMapper::Command do
960
960
  end
961
961
 
962
962
  it "must initialize a new command with the Hash of params and call #sudo_command" do
963
- if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
963
+ if RUBY_VERSION < '3.'
964
964
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
965
965
  else
966
966
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+ require 'command_mapper/types/dec'
3
+
4
+ describe CommandMapper::Types::Dec do
5
+ describe "#initialize" do
6
+ context "when initialized with no keyword arguments" do
7
+ it "must set #range to nil" do
8
+ expect(subject.range).to be(nil)
9
+ end
10
+ end
11
+
12
+ context "when initialized with range: ..." do
13
+ let(:range) { 1.0..1.5 }
14
+
15
+ subject { described_class.new(range: range) }
16
+
17
+ it "must set #range" do
18
+ expect(subject.range).to eq(range)
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "#validate" do
24
+ context "when given an Integer" do
25
+ let(:value) { 1 }
26
+
27
+ it "must return true" do
28
+ expect(subject.validate(value)).to be(true)
29
+ end
30
+
31
+ context "when initialized with range: ..." do
32
+ let(:range) { 2.0..10.0 }
33
+
34
+ subject { described_class.new(range: range) }
35
+
36
+ context "and the value is within the range of values" do
37
+ let(:value) { 4.0 }
38
+
39
+ it "must return true" do
40
+ expect(subject.validate(value)).to be(true)
41
+ end
42
+ end
43
+
44
+ context "but the value is not within the range of values" do
45
+ let(:value) { 0.0 }
46
+
47
+ it "must return [false, \"(...) not within the range of acceptable values (...)\"]" do
48
+ expect(subject.validate(value)).to eq(
49
+ [false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
50
+ )
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ context "when given a String" do
57
+ context "and it contains only digits" do
58
+ let(:value) { "0123456789" }
59
+
60
+ it "must return true" do
61
+ expect(subject.validate(value)).to be(true)
62
+ end
63
+
64
+ context "when initialized with range: ..." do
65
+ let(:range) { 2.0..10.0 }
66
+
67
+ subject { described_class.new(range: range) }
68
+
69
+ context "and the value is within the range of values" do
70
+ let(:value) { '4.0' }
71
+
72
+ it "must return true" do
73
+ expect(subject.validate(value)).to be(true)
74
+ end
75
+ end
76
+
77
+ context "but the value is not within the range of values" do
78
+ let(:value) { '0.0' }
79
+
80
+ it "must return [false, \"(...) not within the range of acceptable values (...)\"]" do
81
+ expect(subject.validate(value)).to eq(
82
+ [false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
83
+ )
84
+ end
85
+ end
86
+ end
87
+
88
+ context "but the String contains a newline" do
89
+ let(:value) { "01234.\n56789" }
90
+
91
+ it "must return [false, \"contains non-decimal characters (...)\"]" do
92
+ expect(subject.validate(value)).to eq(
93
+ [false, "contains non-decimal characters (#{value.inspect})"]
94
+ )
95
+ end
96
+ end
97
+ end
98
+
99
+ context "but it contains non-digits" do
100
+ let(:value) { "12.abc34" }
101
+
102
+ it "must return [false, \"contains non-decimal characters (...)\"]" do
103
+ expect(subject.validate(value)).to eq(
104
+ [false, "contains non-decimal characters (#{value.inspect})"]
105
+ )
106
+ end
107
+ end
108
+ end
109
+
110
+ context "when given another type of Object" do
111
+ context "and it defines a #to_f method" do
112
+ let(:value) { 1 }
113
+
114
+ it "must return true" do
115
+ expect(subject.validate(value)).to be(true)
116
+ end
117
+ end
118
+
119
+ context "when initialized with range: ..." do
120
+ let(:range) { 2.0..10.0 }
121
+
122
+ subject { described_class.new(range: range) }
123
+
124
+ context "and the value is within the range of values" do
125
+ let(:value) { 4 }
126
+
127
+ it "must return true" do
128
+ expect(subject.validate(value)).to be(true)
129
+ end
130
+ end
131
+
132
+ context "but the value is not within the range of values" do
133
+ let(:value) { 0 }
134
+
135
+ it "must return [false, \"(...) not within the range of acceptable values (...)\"]" do
136
+ expect(subject.validate(value)).to eq(
137
+ [false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
138
+ )
139
+ end
140
+ end
141
+ end
142
+
143
+ context "but it does not define a #to_f method" do
144
+ let(:value) { Object.new }
145
+
146
+ it "must return [false, \"value cannot be converted into a Float\"]" do
147
+ expect(subject.validate(value)).to eq(
148
+ [false, "cannot be converted into a Float (#{value.inspect})"]
149
+ )
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "#format" do
156
+ context "when given a String" do
157
+ let(:value) { "12345.67890" }
158
+
159
+ it "must return the same String" do
160
+ expect(subject.format(value)).to eq(value)
161
+ end
162
+ end
163
+
164
+ context "when given an Intger" do
165
+ let(:value) { 12345.67890 }
166
+
167
+ it "must convert the Integer into a String" do
168
+ expect(subject.format(value)).to eq(value.to_s)
169
+ end
170
+ end
171
+
172
+ context "when given another type of Object" do
173
+ let(:value) { 1 }
174
+
175
+ it "must call #to_i then #to_s" do
176
+ expect(subject.format(value)).to eq(value.to_f.to_s)
177
+ end
178
+ end
179
+ end
180
+ end
@@ -3,19 +3,21 @@ require 'command_mapper/types/input_dir'
3
3
 
4
4
  describe CommandMapper::Types::InputDir do
5
5
  describe "#validate" do
6
- context "when given a valid file path" do
7
- let(:value) { __FILE__ }
6
+ context "when given a valid directory path" do
7
+ let(:value) { __dir__ }
8
8
 
9
- it "must return [false, 'directory does not exist (...)']" do
10
- expect(subject.validate(value)).to eq([false, "directory does not exist (#{value.inspect})"])
9
+ it "must return true" do
10
+ expect(subject.validate(value)).to be(true)
11
11
  end
12
12
  end
13
13
 
14
- context "when given a valid directory path" do
15
- let(:value) { __dir__ }
14
+ context "when given a valid file path" do
15
+ let(:value) { __FILE__ }
16
16
 
17
- it "must return true" do
18
- expect(subject.validate(value)).to eq(true)
17
+ it "must return [false, 'directory does not exist (...)']" do
18
+ expect(subject.validate(value)).to eq(
19
+ [false, "directory does not exist (#{value.inspect})"]
20
+ )
19
21
  end
20
22
  end
21
23
 
@@ -23,7 +25,9 @@ describe CommandMapper::Types::InputDir do
23
25
  let(:value) { "/path/does/not/exist" }
24
26
 
25
27
  it "must return [false, 'path does not exist (...)']" do
26
- expect(subject.validate(value)).to eq([false, "path does not exist (#{value.inspect})"])
28
+ expect(subject.validate(value)).to eq(
29
+ [false, "path does not exist (#{value.inspect})"]
30
+ )
27
31
  end
28
32
  end
29
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Postmodern
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-22 00:00:00.000000000 Z
11
+ date: 2022-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,8 +24,8 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- description: Command Mapper maps a command's arguments to Class attributes to allow
28
- safely and securely executing commands.
27
+ description: Command Mapper maps an external command's arguments to Class attributes
28
+ to allow safely and securely executing commands.
29
29
  email: postmodern.mod3@gmail.com
30
30
  executables: []
31
31
  extensions: []
@@ -44,7 +44,7 @@ files:
44
44
  - LICENSE.txt
45
45
  - README.md
46
46
  - Rakefile
47
- - commnad_mapper.gemspec
47
+ - command_mapper.gemspec
48
48
  - examples/grep.rb
49
49
  - gemspec.yml
50
50
  - lib/command_mapper.rb
@@ -56,6 +56,7 @@ files:
56
56
  - lib/command_mapper/option_value.rb
57
57
  - lib/command_mapper/sudo.rb
58
58
  - lib/command_mapper/types.rb
59
+ - lib/command_mapper/types/dec.rb
59
60
  - lib/command_mapper/types/enum.rb
60
61
  - lib/command_mapper/types/hex.rb
61
62
  - lib/command_mapper/types/input_dir.rb
@@ -77,6 +78,7 @@ files:
77
78
  - spec/option_value_spec.rb
78
79
  - spec/spec_helper.rb
79
80
  - spec/sudo_spec.rb
81
+ - spec/types/dec_spec.rb
80
82
  - spec/types/enum_spec.rb
81
83
  - spec/types/hex_spec.rb
82
84
  - spec/types/input_dir_spec.rb
@@ -114,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
116
  - !ruby/object:Gem::Version
115
117
  version: '0'
116
118
  requirements: []
117
- rubygems_version: 3.2.22
119
+ rubygems_version: 3.3.7
118
120
  signing_key:
119
121
  specification_version: 4
120
122
  summary: Safe and secure execution of commands.