Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Break parsing out into its own class. Spec split to come.

Added BSD 2-clause license.
  • Loading branch information...
commit dff532ab4e7f74711bedd7a91814f91746723126 1 parent 0b37c3a
@relistan authored
Showing with 92 additions and 51 deletions.
  1. +27 −0 LICENSE
  2. +1 −1  spec/troll.spec.coffee
  3. +64 −50 src/troll.coffee
View
27 LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2012, Relistan
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
View
2  spec/troll.spec.coffee
@@ -104,7 +104,7 @@ describe 'Troll', ->
@troll.options (t) =>
t.opt 'one', 'Option one', type: 'string'
- expect(_.has(@troll.givenOpts, 'one')).toBe true
+ expect(_.has(@troll.getGivenOpts(), 'one')).toBe true
it 'raises if the same argument is passed more than once', ->
@troll.setCommandLine('test.coffee', '-o', 'shakespeare', '-o', 'foo')
View
114 src/troll.coffee
@@ -155,23 +155,20 @@ class Options
unless _.contains(['string', 'boolean', 'integer', 'float', 'number'], opt.type)
throw new TrollOptError("Invalid type: #{opt.type}")
-class Troll
- constructor: ->
- @opts = new Options()
+
+class Parser
+ constructor: (opts) ->
@parsingStack = []
- @commandLine = _.clone(process.argv).splice(1)
@givenOpts = {}
+ @opts = opts
# ----- Public
- setCommandLine: (@commandLine...) ->
-
- getCommandLine: ->
- @commandLine = _.flatten(x.split('=') for x in @commandLine[1..-1])
-
- parse: ->
- @handle arg for arg in @getCommandLine()
+ parse: (commandLine) ->
+ @handle arg for arg in commandLine
@setDefaultValue(opt) for opt in @opts.optsWithDefaults()
+ @givenOpts
+ # ----- Private
handle: (arg) ->
if arg is '--help'
throw new UsageError()
@@ -201,12 +198,65 @@ class Troll
else
throw new TrollArgumentError("Unknown argument: #{arg}")
+ recognized: (arg) ->
+ bareArg = @stripDashes(arg)
+ (arg.match(/^--/) and @opts.has(bareArg)) or
+ (arg.match(/^-/) and @opts.hasShort(bareArg))
+
+ stripDashes: (arg) ->
+ arg.replace(/^-+/, '')
+
+ haveArgWaiting: ->
+ @parsingStack.length != 0
+
+ setDefaultValue: (opt) ->
+ optSpec = @opts.getParsedOpts()[opt]
+ @givenOpts[opt] = optSpec.default unless _.has(@givenOpts, opt)
+
+ isInt: (n) ->
+ typeof n is 'number' and (n % 1 == 0)
+
+ convert: (opt, value) ->
+ type = @opts.get(opt).type
+ retValue = switch type.toLowerCase()
+ when 'integer' then parseInt(value)
+ when 'float' then parseFloat(value)
+ when 'number' then @convertNumber(number)
+ when 'string' then value
+
+ if _.contains([ 'integer', 'float', 'number' ], type.toLowerCase()) and !(retValue > 0) and !(retValue < 0)
+ throw new TrollArgumentError("#{opt} has an invalid value supplied! Must be a #{type}")
+
+ retValue
+
+ convertNumber: (value) ->
+ if isInt(value)
+ parseInt(value)
+ else
+ parseFloat(value)
+
+
+class Troll
+ constructor: ->
+ @opts = new Options()
+ @commandLine = _.clone(process.argv).splice(1)
+ @parser = new Parser(@opts)
+
+ # ----- Public
+ setCommandLine: (@commandLine...) ->
+
+ getCommandLine: ->
+ @commandLine = _.flatten(x.split('=') for x in @commandLine[1..-1])
+
+ getGivenOpts: ->
+ @parser.givenOpts
+
options: (callback) ->
try
@parseOptions callback
- @parse()
- @opts.validateRequired(@givenOpts)
- return @givenOpts
+ givenOpts = @parser.parse(@getCommandLine())
+ @opts.validateRequired(givenOpts)
+ return givenOpts
catch error
if error instanceof UsageError
@usage()
@@ -249,42 +299,6 @@ class Troll
pad = (" " for x in [strlen..len]).join("")
"#{pad}--#{str}"
- recognized: (arg) ->
- bareArg = @stripDashes(arg)
- (arg.match(/^--/) and @opts.has(bareArg)) or
- (arg.match(/^-/) and @opts.hasShort(bareArg))
-
- stripDashes: (arg) ->
- arg.replace(/^-+/, '')
-
- haveArgWaiting: ->
- @parsingStack.length != 0
-
- setDefaultValue: (opt) ->
- optSpec = @opts.getParsedOpts()[opt]
- @givenOpts[opt] = optSpec.default unless _.has(@givenOpts, opt)
-
- isInt: (n) ->
- typeof n is 'number' and (n % 1 == 0)
-
- convert: (opt, value) ->
- type = @opts.get(opt).type
- retValue = switch type.toLowerCase()
- when 'integer' then parseInt(value)
- when 'float' then parseFloat(value)
- when 'number' then @convertNumber(number)
- when 'string' then value
-
- if _.contains([ 'integer', 'float', 'number' ], type.toLowerCase()) and !(retValue > 0) and !(retValue < 0)
- throw new TrollArgumentError("#{opt} has an invalid value supplied! Must be a #{type}")
-
- retValue
-
- convertNumber: (value) ->
- if isInt(value)
- parseInt(value)
- else
- parseFloat(value)
puts: (args...) ->
console.log args...
Please sign in to comment.
Something went wrong with that request. Please try again.