command_mapper 0.1.1 → 0.2.1
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 +4 -4
- data/.document +3 -0
- data/.github/workflows/ruby.yml +2 -1
- data/ChangeLog.md +32 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +41 -8
- data/examples/grep.rb +62 -0
- data/lib/command_mapper/arg.rb +5 -0
- data/lib/command_mapper/argument.rb +6 -0
- data/lib/command_mapper/command.rb +209 -56
- data/lib/command_mapper/option.rb +50 -13
- data/lib/command_mapper/option_value.rb +22 -0
- data/lib/command_mapper/types/enum.rb +8 -0
- data/lib/command_mapper/types/hex.rb +16 -2
- data/lib/command_mapper/types/input_dir.rb +2 -0
- data/lib/command_mapper/types/input_file.rb +2 -0
- data/lib/command_mapper/types/input_path.rb +2 -0
- data/lib/command_mapper/types/key_value.rb +10 -0
- data/lib/command_mapper/types/key_value_list.rb +2 -0
- data/lib/command_mapper/types/list.rb +10 -0
- data/lib/command_mapper/types/map.rb +12 -1
- data/lib/command_mapper/types/num.rb +28 -1
- data/lib/command_mapper/types/str.rb +10 -1
- data/lib/command_mapper/types/type.rb +4 -0
- data/lib/command_mapper/version.rb +1 -1
- data/spec/commnad_spec.rb +345 -74
- data/spec/option_spec.rb +252 -1
- data/spec/option_value_spec.rb +28 -0
- data/spec/types/hex_spec.rb +59 -1
- data/spec/types/map_spec.rb +2 -2
- data/spec/types/num_spec.rb +93 -3
- metadata +4 -2
    
        data/spec/commnad_spec.rb
    CHANGED
    
    | @@ -7,6 +7,9 @@ describe CommandMapper::Command do | |
| 7 7 | 
             
                  command 'foo'
         | 
| 8 8 | 
             
                end
         | 
| 9 9 |  | 
| 10 | 
            +
                class InheritedCommandName < WithCommandName
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 10 13 | 
             
                class NoCommandName < CommandMapper::Command
         | 
| 11 14 | 
             
                end
         | 
| 12 15 | 
             
              end
         | 
| @@ -51,6 +54,14 @@ describe CommandMapper::Command do | |
| 51 54 | 
             
                    expect(subject.command_name).to eq('foo')
         | 
| 52 55 | 
             
                  end
         | 
| 53 56 | 
             
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                context "when the command class inherits from another command class" do
         | 
| 59 | 
            +
                  let(:command_class) { TestCommand::InheritedCommandName }
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  it "must check the superclass" do
         | 
| 62 | 
            +
                    expect(subject.command_name).to eq("foo")
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 54 65 | 
             
              end
         | 
| 55 66 |  | 
| 56 67 | 
             
              module TestCommand
         | 
| @@ -58,6 +69,20 @@ describe CommandMapper::Command do | |
| 58 69 | 
             
                end
         | 
| 59 70 | 
             
              end
         | 
| 60 71 |  | 
| 72 | 
            +
              module TestCommand
         | 
| 73 | 
            +
                class BaseClassWithOptions < CommandMapper::Command
         | 
| 74 | 
            +
                  option "--foo"
         | 
| 75 | 
            +
                  option "--bar"
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                class InheritedOptions < BaseClassWithOptions
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                class InheritsAndDefinesOptions < BaseClassWithOptions
         | 
| 82 | 
            +
                  option "--baz"
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
             | 
| 61 86 | 
             
              describe ".options" do
         | 
| 62 87 | 
             
                subject { command_class }
         | 
| 63 88 |  | 
| @@ -68,16 +93,6 @@ describe CommandMapper::Command do | |
| 68 93 | 
             
                end
         | 
| 69 94 |  | 
| 70 95 | 
             
                context "and when the command inherits from another command class" do
         | 
| 71 | 
            -
                  module TestCommand
         | 
| 72 | 
            -
                    class BaseClassWithOptions < CommandMapper::Command
         | 
| 73 | 
            -
                      option "--foo"
         | 
| 74 | 
            -
                      option "--bar"
         | 
| 75 | 
            -
                    end
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                    class InheritedOptions < BaseClassWithOptions
         | 
| 78 | 
            -
                    end
         | 
| 79 | 
            -
                  end
         | 
| 80 | 
            -
             | 
| 81 96 | 
             
                  let(:command_class) { TestCommand::InheritedOptions }
         | 
| 82 97 | 
             
                  let(:command_superclass) { TestCommand::BaseClassWithOptions }
         | 
| 83 98 |  | 
| @@ -86,12 +101,6 @@ describe CommandMapper::Command do | |
| 86 101 | 
             
                  end
         | 
| 87 102 |  | 
| 88 103 | 
             
                  context "and when the class defines options of it's own" do
         | 
| 89 | 
            -
                    module TestCommand
         | 
| 90 | 
            -
                      class InheritsAndDefinesOptions < BaseClassWithOptions
         | 
| 91 | 
            -
                        option "--baz"
         | 
| 92 | 
            -
                      end
         | 
| 93 | 
            -
                    end
         | 
| 94 | 
            -
             | 
| 95 104 | 
             
                    let(:command_class) { TestCommand::InheritsAndDefinesOptions }
         | 
| 96 105 |  | 
| 97 106 | 
             
                    it "must copy the options defined in the superclass" do
         | 
| @@ -109,6 +118,38 @@ describe CommandMapper::Command do | |
| 109 118 | 
             
                end
         | 
| 110 119 | 
             
              end
         | 
| 111 120 |  | 
| 121 | 
            +
              describe ".has_option?" do
         | 
| 122 | 
            +
                subject { command_class }
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                let(:name) { :bar }
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                context "when the command has no defined options" do
         | 
| 127 | 
            +
                  let(:command_class) { TestCommand::EmptyCommand }
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                  it "must return false" do
         | 
| 130 | 
            +
                    expect(subject.has_option?(name)).to be(false)
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                context "when the command does have defined options" do
         | 
| 135 | 
            +
                  let(:command_class) { TestCommand::BaseClassWithOptions }
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                  context "and has the option with the given name" do
         | 
| 138 | 
            +
                    it "must return true" do
         | 
| 139 | 
            +
                      expect(subject.has_option?(name)).to be(true)
         | 
| 140 | 
            +
                    end
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                  context "but does not have the option with the given name" do
         | 
| 144 | 
            +
                    let(:name) { :xxx }
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                    it "must return false" do
         | 
| 147 | 
            +
                      expect(subject.has_option?(name)).to be(false)
         | 
| 148 | 
            +
                    end
         | 
| 149 | 
            +
                  end
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
              end
         | 
| 152 | 
            +
             | 
| 112 153 | 
             
              describe ".option" do
         | 
| 113 154 | 
             
                module TestCommand
         | 
| 114 155 | 
             
                  class DefinesItsOwnOptions < CommandMapper::Command
         | 
| @@ -231,6 +272,55 @@ describe CommandMapper::Command do | |
| 231 272 | 
             
                    }.to raise_error(ArgumentError,"option #{flag.inspect} maps to method name ##{name} and cannot override the internal method with same name: ##{name}")
         | 
| 232 273 | 
             
                  end
         | 
| 233 274 | 
             
                end
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                context "when the option name conflicts with another defined argument" do
         | 
| 277 | 
            +
                  let(:command_class) do
         | 
| 278 | 
            +
                    Class.new(described_class) do
         | 
| 279 | 
            +
                      argument :foo
         | 
| 280 | 
            +
                    end
         | 
| 281 | 
            +
                  end
         | 
| 282 | 
            +
             | 
| 283 | 
            +
                  let(:flag) { "--foo" }
         | 
| 284 | 
            +
                  let(:name) { :foo    }
         | 
| 285 | 
            +
             | 
| 286 | 
            +
                  it do
         | 
| 287 | 
            +
                    expect {
         | 
| 288 | 
            +
                      subject.option(flag)
         | 
| 289 | 
            +
                    }.to raise_error(ArgumentError,"option #{flag.inspect} with name #{name.inspect} conflicts with another argument with the same name")
         | 
| 290 | 
            +
                  end
         | 
| 291 | 
            +
                end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                context "when the option name conflicts with another defined subcommand" do
         | 
| 294 | 
            +
                  let(:command_class) do
         | 
| 295 | 
            +
                    Class.new(described_class) do
         | 
| 296 | 
            +
                      subcommand 'foo' do
         | 
| 297 | 
            +
                      end
         | 
| 298 | 
            +
                    end
         | 
| 299 | 
            +
                  end
         | 
| 300 | 
            +
             | 
| 301 | 
            +
                  let(:flag) { "--foo" }
         | 
| 302 | 
            +
                  let(:name) { :foo    }
         | 
| 303 | 
            +
             | 
| 304 | 
            +
                  it do
         | 
| 305 | 
            +
                    expect {
         | 
| 306 | 
            +
                      subject.option(flag)
         | 
| 307 | 
            +
                    }.to raise_error(ArgumentError,"option #{flag.inspect} with name #{name.inspect} conflicts with another subcommand with the same name")
         | 
| 308 | 
            +
                  end
         | 
| 309 | 
            +
                end
         | 
| 310 | 
            +
              end
         | 
| 311 | 
            +
             | 
| 312 | 
            +
              module TestCommand
         | 
| 313 | 
            +
                class BaseClassWithArguments < CommandMapper::Command
         | 
| 314 | 
            +
                  argument :foo
         | 
| 315 | 
            +
                  argument :bar
         | 
| 316 | 
            +
                end
         | 
| 317 | 
            +
             | 
| 318 | 
            +
                class InheritedArguments < BaseClassWithArguments
         | 
| 319 | 
            +
                end
         | 
| 320 | 
            +
             | 
| 321 | 
            +
                class InheritsAndDefinesArguments < BaseClassWithArguments
         | 
| 322 | 
            +
                  argument :baz
         | 
| 323 | 
            +
                end
         | 
| 234 324 | 
             
              end
         | 
| 235 325 |  | 
| 236 326 | 
             
              describe ".arguments" do
         | 
| @@ -243,31 +333,15 @@ describe CommandMapper::Command do | |
| 243 333 | 
             
                end
         | 
| 244 334 |  | 
| 245 335 | 
             
                context "when the comand does have defined arguments" do
         | 
| 246 | 
            -
                   | 
| 247 | 
            -
             | 
| 248 | 
            -
                      argument :foo
         | 
| 249 | 
            -
                      argument :bar
         | 
| 250 | 
            -
                    end
         | 
| 251 | 
            -
             | 
| 252 | 
            -
                    class InheritedOptions < BaseClassWithOptions
         | 
| 253 | 
            -
                    end
         | 
| 254 | 
            -
                  end
         | 
| 255 | 
            -
             | 
| 256 | 
            -
                  let(:command_class) { TestCommand::InheritedOptions }
         | 
| 257 | 
            -
                  let(:command_superclass) { TestCommand::BaseClassWithOptions }
         | 
| 336 | 
            +
                  let(:command_class) { TestCommand::InheritedArguments }
         | 
| 337 | 
            +
                  let(:command_superclass) { TestCommand::BaseClassWithArguments }
         | 
| 258 338 |  | 
| 259 339 | 
             
                  it "must copy the arguments defined in the superclass" do
         | 
| 260 340 | 
             
                    expect(subject.arguments).to eq(command_superclass.arguments)
         | 
| 261 341 | 
             
                  end
         | 
| 262 342 |  | 
| 263 343 | 
             
                  context "and when the class defines arguments of it's own" do
         | 
| 264 | 
            -
                     | 
| 265 | 
            -
                      class InheritsAndDefinesOptions < BaseClassWithOptions
         | 
| 266 | 
            -
                        argument :baz
         | 
| 267 | 
            -
                      end
         | 
| 268 | 
            -
                    end
         | 
| 269 | 
            -
             | 
| 270 | 
            -
                    let(:command_class) { TestCommand::InheritsAndDefinesOptions }
         | 
| 344 | 
            +
                    let(:command_class) { TestCommand::InheritsAndDefinesArguments }
         | 
| 271 345 |  | 
| 272 346 | 
             
                    it "must copy the arguments defined in the superclass" do
         | 
| 273 347 | 
             
                      expect(subject.arguments).to include(command_superclass.arguments)
         | 
| @@ -284,6 +358,38 @@ describe CommandMapper::Command do | |
| 284 358 | 
             
                end
         | 
| 285 359 | 
             
              end
         | 
| 286 360 |  | 
| 361 | 
            +
              describe ".has_argument?" do
         | 
| 362 | 
            +
                subject { command_class }
         | 
| 363 | 
            +
             | 
| 364 | 
            +
                let(:name) { :bar }
         | 
| 365 | 
            +
             | 
| 366 | 
            +
                context "when the command has no defined arguments" do
         | 
| 367 | 
            +
                  let(:command_class) { TestCommand::EmptyCommand }
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                  it "must return false" do
         | 
| 370 | 
            +
                    expect(subject.has_argument?(name)).to be(false)
         | 
| 371 | 
            +
                  end
         | 
| 372 | 
            +
                end
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                context "when the command does have defined arguments" do
         | 
| 375 | 
            +
                  let(:command_class) { TestCommand::BaseClassWithArguments }
         | 
| 376 | 
            +
             | 
| 377 | 
            +
                  context "and has the argument with the given name" do
         | 
| 378 | 
            +
                    it "must return true" do
         | 
| 379 | 
            +
                      expect(subject.has_argument?(name)).to be(true)
         | 
| 380 | 
            +
                    end
         | 
| 381 | 
            +
                  end
         | 
| 382 | 
            +
             | 
| 383 | 
            +
                  context "but does not have the argument with the given name" do
         | 
| 384 | 
            +
                    let(:name) { :xxx }
         | 
| 385 | 
            +
             | 
| 386 | 
            +
                    it "must return false" do
         | 
| 387 | 
            +
                      expect(subject.has_argument?(name)).to be(false)
         | 
| 388 | 
            +
                    end
         | 
| 389 | 
            +
                  end
         | 
| 390 | 
            +
                end
         | 
| 391 | 
            +
              end
         | 
| 392 | 
            +
             | 
| 287 393 | 
             
              describe ".argument" do
         | 
| 288 394 | 
             
                module TestCommand
         | 
| 289 395 | 
             
                  class DefinesArgument < CommandMapper::Command
         | 
| @@ -346,6 +452,59 @@ describe CommandMapper::Command do | |
| 346 452 | 
             
                    }.to raise_error(ArgumentError,"argument #{name.inspect} cannot override internal method with same name: ##{name}")
         | 
| 347 453 | 
             
                  end
         | 
| 348 454 | 
             
                end
         | 
| 455 | 
            +
             | 
| 456 | 
            +
                context "when the argument name conflicts with another defined option" do
         | 
| 457 | 
            +
                  let(:command_class) do
         | 
| 458 | 
            +
                    Class.new(described_class) do
         | 
| 459 | 
            +
                      option '--foo'
         | 
| 460 | 
            +
                    end
         | 
| 461 | 
            +
                  end
         | 
| 462 | 
            +
             | 
| 463 | 
            +
                  let(:name) { :foo }
         | 
| 464 | 
            +
             | 
| 465 | 
            +
                  it do
         | 
| 466 | 
            +
                    expect {
         | 
| 467 | 
            +
                      subject.argument(name)
         | 
| 468 | 
            +
                    }.to raise_error(ArgumentError,"argument #{name.inspect} conflicts with another option with the same name")
         | 
| 469 | 
            +
                  end
         | 
| 470 | 
            +
                end
         | 
| 471 | 
            +
             | 
| 472 | 
            +
                context "when the argument name conflicts with another defined subcommand" do
         | 
| 473 | 
            +
                  let(:command_class) do
         | 
| 474 | 
            +
                    Class.new(described_class) do
         | 
| 475 | 
            +
                      subcommand 'foo' do
         | 
| 476 | 
            +
                      end
         | 
| 477 | 
            +
                    end
         | 
| 478 | 
            +
                  end
         | 
| 479 | 
            +
             | 
| 480 | 
            +
                  let(:name) { :foo }
         | 
| 481 | 
            +
             | 
| 482 | 
            +
                  it do
         | 
| 483 | 
            +
                    expect {
         | 
| 484 | 
            +
                      subject.argument(name)
         | 
| 485 | 
            +
                    }.to raise_error(ArgumentError,"argument #{name.inspect} conflicts with another subcommand with the same name")
         | 
| 486 | 
            +
                  end
         | 
| 487 | 
            +
                end
         | 
| 488 | 
            +
              end
         | 
| 489 | 
            +
             | 
| 490 | 
            +
              module TestCommand
         | 
| 491 | 
            +
                class BaseClassWithSubcommands < CommandMapper::Command
         | 
| 492 | 
            +
                  subcommand :foo do
         | 
| 493 | 
            +
                  end
         | 
| 494 | 
            +
             | 
| 495 | 
            +
                  subcommand :bar do
         | 
| 496 | 
            +
                  end
         | 
| 497 | 
            +
                end
         | 
| 498 | 
            +
             | 
| 499 | 
            +
                class InheritedSubcommands < BaseClassWithSubcommands
         | 
| 500 | 
            +
                end
         | 
| 501 | 
            +
             | 
| 502 | 
            +
                class InheritsAndDefinesSubcommands < BaseClassWithSubcommands
         | 
| 503 | 
            +
             | 
| 504 | 
            +
                  subcommand :baz do
         | 
| 505 | 
            +
                  end
         | 
| 506 | 
            +
             | 
| 507 | 
            +
                end
         | 
| 349 508 | 
             
              end
         | 
| 350 509 |  | 
| 351 510 | 
             
              describe ".subcommands" do
         | 
| @@ -358,37 +517,15 @@ describe CommandMapper::Command do | |
| 358 517 | 
             
                end
         | 
| 359 518 |  | 
| 360 519 | 
             
                context "when the comand does have defined subcommands" do
         | 
| 361 | 
            -
                   | 
| 362 | 
            -
             | 
| 363 | 
            -
                      subcommand :foo do
         | 
| 364 | 
            -
                      end
         | 
| 365 | 
            -
             | 
| 366 | 
            -
                      subcommand :bar do
         | 
| 367 | 
            -
                      end
         | 
| 368 | 
            -
                    end
         | 
| 369 | 
            -
             | 
| 370 | 
            -
                    class InheritedOptions < BaseClassWithOptions
         | 
| 371 | 
            -
                    end
         | 
| 372 | 
            -
                  end
         | 
| 373 | 
            -
             | 
| 374 | 
            -
                  let(:command_class) { TestCommand::InheritedOptions }
         | 
| 375 | 
            -
                  let(:command_superclass) { TestCommand::BaseClassWithOptions }
         | 
| 520 | 
            +
                  let(:command_class) { TestCommand::InheritedSubcommands }
         | 
| 521 | 
            +
                  let(:command_superclass) { TestCommand::BaseClassWithSubcommands }
         | 
| 376 522 |  | 
| 377 523 | 
             
                  it "must copy the subcommands defined in the superclass" do
         | 
| 378 524 | 
             
                    expect(subject.subcommands).to eq(command_superclass.subcommands)
         | 
| 379 525 | 
             
                  end
         | 
| 380 526 |  | 
| 381 527 | 
             
                  context "and when the class defines subcommands of it's own" do
         | 
| 382 | 
            -
                     | 
| 383 | 
            -
                      class InheritsAndDefinesOptions < BaseClassWithOptions
         | 
| 384 | 
            -
             | 
| 385 | 
            -
                        subcommand :baz do
         | 
| 386 | 
            -
                        end
         | 
| 387 | 
            -
             | 
| 388 | 
            -
                      end
         | 
| 389 | 
            -
                    end
         | 
| 390 | 
            -
             | 
| 391 | 
            -
                    let(:command_class) { TestCommand::InheritsAndDefinesOptions }
         | 
| 528 | 
            +
                    let(:command_class) { TestCommand::InheritsAndDefinesSubcommands }
         | 
| 392 529 |  | 
| 393 530 | 
             
                    it "must copy the subcommands defined in the superclass" do
         | 
| 394 531 | 
             
                      expect(subject.subcommands).to include(command_superclass.subcommands)
         | 
| @@ -405,6 +542,38 @@ describe CommandMapper::Command do | |
| 405 542 | 
             
                end
         | 
| 406 543 | 
             
              end
         | 
| 407 544 |  | 
| 545 | 
            +
              describe ".has_subcommand?" do
         | 
| 546 | 
            +
                subject { command_class }
         | 
| 547 | 
            +
             | 
| 548 | 
            +
                let(:name) { :bar }
         | 
| 549 | 
            +
             | 
| 550 | 
            +
                context "when the command has no defined subcommands" do
         | 
| 551 | 
            +
                  let(:command_class) { TestCommand::EmptyCommand }
         | 
| 552 | 
            +
             | 
| 553 | 
            +
                  it "must return false" do
         | 
| 554 | 
            +
                    expect(subject.has_subcommand?(name)).to be(false)
         | 
| 555 | 
            +
                  end
         | 
| 556 | 
            +
                end
         | 
| 557 | 
            +
             | 
| 558 | 
            +
                context "when the command does have defined subcommands" do
         | 
| 559 | 
            +
                  let(:command_class) { TestCommand::BaseClassWithSubcommands }
         | 
| 560 | 
            +
             | 
| 561 | 
            +
                  context "and has the subcommand with the given name" do
         | 
| 562 | 
            +
                    it "must return true" do
         | 
| 563 | 
            +
                      expect(subject.has_subcommand?(name)).to be(true)
         | 
| 564 | 
            +
                    end
         | 
| 565 | 
            +
                  end
         | 
| 566 | 
            +
             | 
| 567 | 
            +
                  context "but does not have the subcommand with the given name" do
         | 
| 568 | 
            +
                    let(:name) { :xxx }
         | 
| 569 | 
            +
             | 
| 570 | 
            +
                    it "must return false" do
         | 
| 571 | 
            +
                      expect(subject.has_subcommand?(name)).to be(false)
         | 
| 572 | 
            +
                    end
         | 
| 573 | 
            +
                  end
         | 
| 574 | 
            +
                end
         | 
| 575 | 
            +
              end
         | 
| 576 | 
            +
             | 
| 408 577 | 
             
              describe ".subcommand" do
         | 
| 409 578 | 
             
                module TestCommand
         | 
| 410 579 | 
             
                  class DefinesSubcommand < CommandMapper::Command
         | 
| @@ -556,11 +725,45 @@ describe CommandMapper::Command do | |
| 556 725 |  | 
| 557 726 | 
             
                  it do
         | 
| 558 727 | 
             
                    expect {
         | 
| 559 | 
            -
                       | 
| 728 | 
            +
                      subject.subcommand(name) do
         | 
| 560 729 | 
             
                      end
         | 
| 561 730 | 
             
                    }.to raise_error(ArgumentError,"subcommand #{name.inspect} maps to method name ##{method_name} and cannot override the internal method with same name: ##{method_name}")
         | 
| 562 731 | 
             
                  end
         | 
| 563 732 | 
             
                end
         | 
| 733 | 
            +
             | 
| 734 | 
            +
                context "when the subcommand name conflicts with another defined option" do
         | 
| 735 | 
            +
                  let(:command_class) do
         | 
| 736 | 
            +
                    Class.new(described_class) do
         | 
| 737 | 
            +
                      option '--foo'
         | 
| 738 | 
            +
                    end
         | 
| 739 | 
            +
                  end
         | 
| 740 | 
            +
             | 
| 741 | 
            +
                  let(:name) { 'foo' }
         | 
| 742 | 
            +
             | 
| 743 | 
            +
                  it do
         | 
| 744 | 
            +
                    expect {
         | 
| 745 | 
            +
                      subject.subcommand(name) do
         | 
| 746 | 
            +
                      end
         | 
| 747 | 
            +
                    }.to raise_error(ArgumentError,"subcommand #{name.inspect} conflicts with another option with the same name")
         | 
| 748 | 
            +
                  end
         | 
| 749 | 
            +
                end
         | 
| 750 | 
            +
             | 
| 751 | 
            +
                context "when the subcommand name conflicts with another defined argument" do
         | 
| 752 | 
            +
                  let(:command_class) do
         | 
| 753 | 
            +
                    Class.new(described_class) do
         | 
| 754 | 
            +
                      argument :foo
         | 
| 755 | 
            +
                    end
         | 
| 756 | 
            +
                  end
         | 
| 757 | 
            +
             | 
| 758 | 
            +
                  let(:name) { 'foo' }
         | 
| 759 | 
            +
             | 
| 760 | 
            +
                  it do
         | 
| 761 | 
            +
                    expect {
         | 
| 762 | 
            +
                      subject.subcommand(name) do
         | 
| 763 | 
            +
                      end
         | 
| 764 | 
            +
                    }.to raise_error(ArgumentError,"subcommand #{name.inspect} conflicts with another argument with the same name")
         | 
| 765 | 
            +
                  end
         | 
| 766 | 
            +
                end
         | 
| 564 767 | 
             
              end
         | 
| 565 768 |  | 
| 566 769 | 
             
              module TestCommand
         | 
| @@ -604,8 +807,8 @@ describe CommandMapper::Command do | |
| 604 807 | 
             
                    {opt1: opt1, arg1: arg1}
         | 
| 605 808 | 
             
                  end
         | 
| 606 809 |  | 
| 607 | 
            -
                  it "must initialize a new command with the Hash of params and call # | 
| 608 | 
            -
                    if RUBY_VERSION < '3.'
         | 
| 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'
         | 
| 609 812 | 
             
                      expect(subject).to receive(:new).with({},params).and_return(command_instance)
         | 
| 610 813 | 
             
                    else
         | 
| 611 814 | 
             
                      expect(subject).to receive(:new).with(params).and_return(command_instance)
         | 
| @@ -622,7 +825,7 @@ describe CommandMapper::Command do | |
| 622 825 | 
             
                    {opt1: opt1, arg1: arg1}
         | 
| 623 826 | 
             
                  end
         | 
| 624 827 |  | 
| 625 | 
            -
                  it "must initialize a new command with the keyword arguments and call # | 
| 828 | 
            +
                  it "must initialize a new command with the keyword arguments and call #run_command" do
         | 
| 626 829 | 
             
                    expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
         | 
| 627 830 | 
             
                    expect(command_instance).to receive(:run_command).and_return(return_value)
         | 
| 628 831 |  | 
| @@ -631,6 +834,44 @@ describe CommandMapper::Command do | |
| 631 834 | 
             
                end
         | 
| 632 835 | 
             
              end
         | 
| 633 836 |  | 
| 837 | 
            +
              describe ".spawn" do
         | 
| 838 | 
            +
                let(:command_instance) { double(:command_instance) }
         | 
| 839 | 
            +
                let(:return_value)     { double(:boolean)          }
         | 
| 840 | 
            +
             | 
| 841 | 
            +
                subject { command_class }
         | 
| 842 | 
            +
             | 
| 843 | 
            +
                context "when called with a Hash of params" do
         | 
| 844 | 
            +
                  let(:params) do
         | 
| 845 | 
            +
                    {opt1: opt1, arg1: arg1}
         | 
| 846 | 
            +
                  end
         | 
| 847 | 
            +
             | 
| 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'
         | 
| 850 | 
            +
                      expect(subject).to receive(:new).with({},params).and_return(command_instance)
         | 
| 851 | 
            +
                    else
         | 
| 852 | 
            +
                      expect(subject).to receive(:new).with(params).and_return(command_instance)
         | 
| 853 | 
            +
                    end
         | 
| 854 | 
            +
             | 
| 855 | 
            +
                    expect(command_instance).to receive(:spawn_command).and_return(return_value)
         | 
| 856 | 
            +
             | 
| 857 | 
            +
                    expect(subject.spawn(params)).to be(return_value)
         | 
| 858 | 
            +
                  end
         | 
| 859 | 
            +
                end
         | 
| 860 | 
            +
             | 
| 861 | 
            +
                context "when called with keyword aguments" do
         | 
| 862 | 
            +
                  let(:kwargs) do
         | 
| 863 | 
            +
                    {opt1: opt1, arg1: arg1}
         | 
| 864 | 
            +
                  end
         | 
| 865 | 
            +
             | 
| 866 | 
            +
                  it "must initialize a new command with the keyword arguments and call #spawn_command" do
         | 
| 867 | 
            +
                    expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
         | 
| 868 | 
            +
                    expect(command_instance).to receive(:spawn_command).and_return(return_value)
         | 
| 869 | 
            +
             | 
| 870 | 
            +
                    expect(subject.spawn(**kwargs)).to be(return_value)
         | 
| 871 | 
            +
                  end
         | 
| 872 | 
            +
                end
         | 
| 873 | 
            +
              end
         | 
| 874 | 
            +
             | 
| 634 875 | 
             
              describe ".capture" do
         | 
| 635 876 | 
             
                let(:command_instance) { double(:command_instance) }
         | 
| 636 877 | 
             
                let(:return_value)     { double(:string)           }
         | 
| @@ -642,8 +883,8 @@ describe CommandMapper::Command do | |
| 642 883 | 
             
                    {opt1: opt1, arg1: arg1}
         | 
| 643 884 | 
             
                  end
         | 
| 644 885 |  | 
| 645 | 
            -
                  it "must initialize a new command with the Hash of params and call # | 
| 646 | 
            -
                    if RUBY_VERSION < '3.'
         | 
| 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'
         | 
| 647 888 | 
             
                      expect(subject).to receive(:new).with({},params).and_return(command_instance)
         | 
| 648 889 | 
             
                    else
         | 
| 649 890 | 
             
                      expect(subject).to receive(:new).with(params).and_return(command_instance)
         | 
| @@ -660,7 +901,7 @@ describe CommandMapper::Command do | |
| 660 901 | 
             
                    {opt1: opt1, arg1: arg1}
         | 
| 661 902 | 
             
                  end
         | 
| 662 903 |  | 
| 663 | 
            -
                  it "must initialize a new command with the keyword arguments and call # | 
| 904 | 
            +
                  it "must initialize a new command with the keyword arguments and call #capture_command" do
         | 
| 664 905 | 
             
                    expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
         | 
| 665 906 | 
             
                    expect(command_instance).to receive(:capture_command).and_return(return_value)
         | 
| 666 907 |  | 
| @@ -680,8 +921,8 @@ describe CommandMapper::Command do | |
| 680 921 | 
             
                    {opt1: opt1, arg1: arg1}
         | 
| 681 922 | 
             
                  end
         | 
| 682 923 |  | 
| 683 | 
            -
                  it "must initialize a new command with the Hash of params and call # | 
| 684 | 
            -
                    if RUBY_VERSION < '3.'
         | 
| 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'
         | 
| 685 926 | 
             
                      expect(subject).to receive(:new).with({},params).and_return(command_instance)
         | 
| 686 927 | 
             
                    else
         | 
| 687 928 | 
             
                      expect(subject).to receive(:new).with(params).and_return(command_instance)
         | 
| @@ -698,7 +939,7 @@ describe CommandMapper::Command do | |
| 698 939 | 
             
                    {opt1: opt1, arg1: arg1}
         | 
| 699 940 | 
             
                  end
         | 
| 700 941 |  | 
| 701 | 
            -
                  it "must initialize a new command with the keyword arguments and call # | 
| 942 | 
            +
                  it "must initialize a new command with the keyword arguments and call #popen_command" do
         | 
| 702 943 | 
             
                    expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
         | 
| 703 944 | 
             
                    expect(command_instance).to receive(:popen_command).and_return(return_value)
         | 
| 704 945 |  | 
| @@ -718,8 +959,8 @@ describe CommandMapper::Command do | |
| 718 959 | 
             
                    {opt1: opt1, arg1: arg1}
         | 
| 719 960 | 
             
                  end
         | 
| 720 961 |  | 
| 721 | 
            -
                  it "must initialize a new command with the Hash of params and call # | 
| 722 | 
            -
                    if RUBY_VERSION < '3.'
         | 
| 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'
         | 
| 723 964 | 
             
                      expect(subject).to receive(:new).with({},params).and_return(command_instance)
         | 
| 724 965 | 
             
                    else
         | 
| 725 966 | 
             
                      expect(subject).to receive(:new).with(params).and_return(command_instance)
         | 
| @@ -736,7 +977,7 @@ describe CommandMapper::Command do | |
| 736 977 | 
             
                    {opt1: opt1, arg1: arg1}
         | 
| 737 978 | 
             
                  end
         | 
| 738 979 |  | 
| 739 | 
            -
                  it "must initialize a new command with the keyword arguments and call # | 
| 980 | 
            +
                  it "must initialize a new command with the keyword arguments and call #sudo_command" do
         | 
| 740 981 | 
             
                    expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
         | 
| 741 982 | 
             
                    expect(command_instance).to receive(:sudo_command).and_return(return_value)
         | 
| 742 983 |  | 
| @@ -922,6 +1163,26 @@ describe CommandMapper::Command do | |
| 922 1163 | 
             
                      }.to raise_error(ArgumentRequired,"argument arg2 is required")
         | 
| 923 1164 | 
             
                    end
         | 
| 924 1165 | 
             
                  end
         | 
| 1166 | 
            +
             | 
| 1167 | 
            +
                  context "but the command has un-required arguments that repeat" do
         | 
| 1168 | 
            +
                    module TestCommand
         | 
| 1169 | 
            +
                      class CommandWithUnRequiredRepeatingArguments < CommandMapper::Command
         | 
| 1170 | 
            +
                        command "test" do
         | 
| 1171 | 
            +
                          argument :arg1, required: false
         | 
| 1172 | 
            +
                          argument :arg2, required: false, repeats: true
         | 
| 1173 | 
            +
                          argument :arg3, required: false
         | 
| 1174 | 
            +
                        end
         | 
| 1175 | 
            +
                      end
         | 
| 1176 | 
            +
                    end
         | 
| 1177 | 
            +
             | 
| 1178 | 
            +
                    let(:command_class) { TestCommand::CommandWithUnRequiredRepeatingArguments }
         | 
| 1179 | 
            +
             | 
| 1180 | 
            +
                    subject { command_class.new(arg1: nil, arg2: nil, arg3: nil) }
         | 
| 1181 | 
            +
             | 
| 1182 | 
            +
                    it "must omit the un-required repeating arguments that are not set" do
         | 
| 1183 | 
            +
                      expect(subject.command_argv).to eq([subject.class.command_name])
         | 
| 1184 | 
            +
                    end
         | 
| 1185 | 
            +
                  end
         | 
| 925 1186 | 
             
                end
         | 
| 926 1187 |  | 
| 927 1188 | 
             
                context "when the command is initialized with the command_path: keyword" do
         | 
| @@ -1109,12 +1370,22 @@ describe CommandMapper::Command do | |
| 1109 1370 | 
             
                subject { command_class.new({opt1: opt1, arg1: arg1}, command_env: env) }
         | 
| 1110 1371 |  | 
| 1111 1372 | 
             
                it "must pass the command's env and argv to Kenrel.system" do
         | 
| 1112 | 
            -
                  expect( | 
| 1373 | 
            +
                  expect(Kernel).to receive(:system).with(env,*subject.command_argv)
         | 
| 1113 1374 |  | 
| 1114 1375 | 
             
                  subject.run_command
         | 
| 1115 1376 | 
             
                end
         | 
| 1116 1377 | 
             
              end
         | 
| 1117 1378 |  | 
| 1379 | 
            +
              describe "#spawn_command" do
         | 
| 1380 | 
            +
                subject { command_class.new({opt1: opt1, arg1: arg1}, command_env: env) }
         | 
| 1381 | 
            +
             | 
| 1382 | 
            +
                it "must pass the command's env and argv to Kenrel.system" do
         | 
| 1383 | 
            +
                  expect(Process).to receive(:spawn).with(env,*subject.command_argv)
         | 
| 1384 | 
            +
             | 
| 1385 | 
            +
                  subject.spawn_command
         | 
| 1386 | 
            +
                end
         | 
| 1387 | 
            +
              end
         | 
| 1388 | 
            +
             | 
| 1118 1389 | 
             
              describe "#capture_command" do
         | 
| 1119 1390 | 
             
                subject { command_class.new({opt1: opt1, arg1: arg1}, command_env: env) }
         | 
| 1120 1391 |  |