dreck 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eaaec798888ca9a462d16bf380853aafa47eba29
4
+ data.tar.gz: e3657ca419dc6a331a292af9778402d1e6d37e6e
5
+ SHA512:
6
+ metadata.gz: f77bdc510acefb7c00223ed0e49d160c9f19749e92a9ea100539cdcfd0cb9798b1f11314828a906a67771f4cc3e7460939c2499b046680d93bc839a3df35ed85
7
+ data.tar.gz: 0ced355c2e535154d7702ca4e47eb1dc3469aaa8789b05ec367d84e16b462827a784aab812efeefcb316c0f8923cd7bdad936d8a4a2387589f8337951fdc8285
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private --markup-provider=redcarpet --markup=markdown - *.md LICENSE
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 William Woodruff <william @ yossarian.net>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ dreck
2
+ =====
3
+
4
+ A stupid parser for trailing arguments.
5
+
6
+ ### Motivation
7
+
8
+ There are lots of good argument parsers for Ruby:
9
+ [OptionParser](https://ruby-doc.org/stdlib/libdoc/optparse/rdoc/OptionParser.html),
10
+ [Slop](https://github.com/leejarvis/slop), [trollop](https://manageiq.github.io/trollop/),
11
+ [cocaine](https://github.com/thoughtbot/cocaine), etc.
12
+
13
+ Most of these are great for parsing and typechecking options, but none provide a good
14
+ interface to the arguments that often *trail* the options.
15
+
16
+ Dreck does exactly that. Give it a specification of arguments (and their
17
+ types) to expect, and it will give you a nicely typechecked result.
18
+
19
+ ### Installation
20
+
21
+ ```bash
22
+ $ gem install dreck
23
+ ```
24
+
25
+ ### Usage
26
+
27
+ Dreck is best used in conjunction with an option parser like
28
+ [Slop](https://github.com/leejarvis/slop), which can provide an array of
29
+ arguments with options already filtered out:
30
+
31
+ ```ruby
32
+ opts = Slop.parse do |s|
33
+ # ...
34
+ end
35
+
36
+ opts.args # => [ "/dev/urandom", "/dev/sda", "512" ]
37
+
38
+ results = Dreck.parse opts.args, strict: true do
39
+ file :input
40
+ symbol :output
41
+ int :blocksize
42
+ end
43
+
44
+ results[:input] # => "/dev/urandom"
45
+ results[:output] # => :"/dev/sda"
46
+ results[:blocksize] # => 512
47
+ ```
48
+
49
+ Lists are also supported:
50
+
51
+ ```ruby
52
+ result = Dreck.parse opts.args do
53
+ string :uuid
54
+ list :file, :inputs, count: 2
55
+ list :int, :nums
56
+ end
57
+
58
+ result[:id] # => "01aa84ab-5b2c-4861-adc9-fcc6990a5ca5"
59
+ result[:inputs] # => ["/tmp/foo", "/tmp/bar"]
60
+ result[:nums] # => [1, 2, 3, 4, 5]
61
+ ```
data/lib/dreck.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "dreck/result"
4
+
5
+ # The primary namespace for {Dreck}.
6
+ module Dreck
7
+ # {Dreck}'s current version.
8
+ VERSION = "0.0.1"
9
+
10
+ # Parse the given arguments and produce a result.
11
+ # @param args [Array<String>] the arguments to parse
12
+ # @param strict [Boolean] whether or not to be strict about argument absorption
13
+ # @return [Result] the parsing result
14
+ def self.parse(args = ARGV, strict: true, &block)
15
+ result = Result.new(args, strict: strict)
16
+ result.instance_eval(&block)
17
+ result.parse!
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dreck
4
+ # A generic error class for all {Dreck} errors.
5
+ class DreckError < RuntimeError
6
+ end
7
+
8
+ # Raised during argument absorption if arguments are either left over
9
+ # or are insufficient to populate the expected results.
10
+ class AbsorptionError < DreckError
11
+ end
12
+
13
+ # Raised during parsing if a given type cannot be produced from the corresponding
14
+ # argument.
15
+ class ParserError < DreckError
16
+ end
17
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "parser"
4
+
5
+ module Dreck
6
+ # Type and other constraint testing methods for {Dreck}.
7
+ class Parser
8
+ # @return [Array<Symbol>] the scalar types recognized by {Dreck}.
9
+ # @api private
10
+ SCALAR_TYPES = %i[int float path file directory symbol string].freeze
11
+
12
+ class << self
13
+ # @param int [String] the string to coerce into an integer
14
+ # @return [Integer] the integer value of the string
15
+ # @raise [ParserError] if the string cannot be converted
16
+ def parse_int(int)
17
+ Integer int rescue raise ParserError, "#{int}: not an integer"
18
+ end
19
+
20
+ # @param float [String] the string to coerce into a float
21
+ # @return [Float] the floating-point value of the string
22
+ # @raise [ParserError] if the string cannot be converted
23
+ def parse_float(float)
24
+ Float float rescue raise ParserError, "#{float}: not a float"
25
+ end
26
+
27
+ # @param path [String] the string to check for path-ness
28
+ # @return [String] the string itself, if it is a path
29
+ # @raise [ParserError] if the string is not a valid path on disk
30
+ def parse_path(path)
31
+ raise ParserError, "#{path}: no such path" unless File.exist?(path)
32
+ path
33
+ end
34
+
35
+ # @param file [String] the string to check for file-ness
36
+ # @return [String] the string itself, if it is a filename
37
+ # @raise [ParserError] if the string is not a valid regular file on disk
38
+ def parse_file(file)
39
+ raise ParserError, "#{file}: no such file" unless File.file?(file)
40
+ file
41
+ end
42
+
43
+ # @param dir [String] the string to check for directory-ness
44
+ # @return [String] the string itself, if it is a directory
45
+ # @raise [ParserError] if the string is not a valid directory on disk
46
+ def parse_directory(dir)
47
+ raise ParserError, "#{dir}: no such directory" unless File.directory?(dir)
48
+ dir
49
+ end
50
+
51
+ # @param sym [String] the string to coerce into a symbol
52
+ # @return [Symbol] the coerced symbol
53
+ def parse_symbol(sym)
54
+ sym.to_sym
55
+ end
56
+
57
+ # @param str [String] the string to coerce into a string
58
+ # @return [String] the coerced string
59
+ # @note This does nothing.
60
+ def parse_string(str)
61
+ str
62
+ end
63
+
64
+ # @param type [Symbol] the type of each member of the list
65
+ # @param list [Array<String>] the value of each member
66
+ # @return [Object] the coerced results
67
+ def parse_list(type, list)
68
+ list.map { |arg| send "parse_#{type}", arg }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "exceptions"
4
+ require_relative "parser"
5
+
6
+ module Dreck
7
+ # Represents the state and results of a {Dreck} parse.
8
+ class Result
9
+ # @return [Array] the type, name, and count information for arguments
10
+ attr_reader :expected
11
+
12
+ # @return [Hash] the parsing results hash
13
+ attr_reader :results
14
+
15
+ # @param args [Array<String>] the arguments to parse
16
+ # @param strict [Boolean] whether or not to be strict about argument absorption
17
+ def initialize(args, strict: true)
18
+ @args = args.dup
19
+ @strict = strict
20
+ @expected = []
21
+ @results = {}
22
+ end
23
+
24
+ # @param key [Symbol] the named argument to look up
25
+ # @return [Object] the parsed value
26
+ def [](key)
27
+ @results[key]
28
+ end
29
+
30
+ # @return [Boolean] whether the results were parsed strictly
31
+ def strict?
32
+ @strict
33
+ end
34
+
35
+ Parser::SCALAR_TYPES.each do |type|
36
+ define_method type do |sym|
37
+ @expected << [type, sym]
38
+ end
39
+ end
40
+
41
+ # Specifies a list of arguments of a given type to be parsed.
42
+ # @param type [Symbol] the type of the arguments
43
+ # @param sym [Symbol] the name of the argument in {results}
44
+ # @param count [Integer] the number of arguments in the list
45
+ def list(type, sym, count: nil)
46
+ @expected << [:list, type, sym, count]
47
+ end
48
+
49
+ # Perform the actual parsing.
50
+ # @return [Result] this instance
51
+ # @api private
52
+ def parse!
53
+ check_absorption!
54
+
55
+ @expected.each do |type, *rest|
56
+ case type
57
+ when :list
58
+ parse_list!(*rest)
59
+ else
60
+ parse_type!(type, *rest)
61
+ end
62
+ end
63
+
64
+ self
65
+ end
66
+
67
+ # Check whether the expected arguments absorb all supplied arguments.
68
+ # @raise [AbsoptionError] if absorption fails and {strict?} is not true
69
+ # @api private
70
+ def check_absorption!
71
+ count = count_expected
72
+
73
+ return if count.nil?
74
+ raise AbsoptionError, "too few arguments" if count > @args.size && strict?
75
+ raise AbsoptionError, "too many arguments" if count < @args.size && strict?
76
+ end
77
+
78
+ # Count the number of arguments expected to be supplied.
79
+ # @raise [Integer, nil] the number of expected arguments, or nil if a list
80
+ # of indeterminate size is specified
81
+ # @api private
82
+ def count_expected
83
+ @expected.inject(0) do |n, exp|
84
+ case exp.first
85
+ when :list
86
+ # if the list is greedy, all arguments have to be absorbed
87
+ break unless exp[3]
88
+
89
+ n + exp[3]
90
+ else
91
+ n + 1
92
+ end
93
+ end
94
+ end
95
+
96
+ # Parse a one or more expected arguments of a given type and add them to
97
+ # the results.
98
+ # @param type [Symbol] the type of the individual elements of the list
99
+ # @param sym [Symbol] the key to store the results under in {results}
100
+ # @param count [Integer, nil] the size of the list, or nil if the list
101
+ # absorbs all following arguments
102
+ # @api private
103
+ def parse_list!(type, sym, count)
104
+ args = if count
105
+ @args.shift count
106
+ else
107
+ @args
108
+ end
109
+
110
+ @results[sym] = Parser.parse_list type, args
111
+ end
112
+
113
+ # Parse one expected argument of a given scalar type and add it to the results.
114
+ # @param type [Symbol] the type of the expected argument
115
+ # @param sym [Symbol] the key to store the result under in {results}
116
+ # @api private
117
+ def parse_type!(type, sym)
118
+ arg = @args.shift
119
+
120
+ @results[sym] = Parser.send("parse_#{type}", arg)
121
+ end
122
+ end
123
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dreck
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - William Woodruff
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Typechecks and coerces non-option arguments.
14
+ email: william@tuffbizz.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".yardopts"
20
+ - LICENSE
21
+ - README.md
22
+ - lib/dreck.rb
23
+ - lib/dreck/exceptions.rb
24
+ - lib/dreck/parser.rb
25
+ - lib/dreck/result.rb
26
+ homepage: https://github.com/woodruffw/dreck
27
+ licenses:
28
+ - MIT
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: 2.3.0
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.6.11
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: dreck - A stupid parser for trailing arguments.
50
+ test_files: []