command_mapper 0.2.1 → 0.3.0

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.
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.