samovar 1.1.0 → 1.1.1

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
  SHA1:
3
- metadata.gz: 245b832e19301eafe975c8bc751f3d8f7c5f5fab
4
- data.tar.gz: 8db97750516f551f87c9d614958e53e191a0d665
3
+ metadata.gz: df07fe3139c96d3f34b9e4d1ae5416e1f311eb2f
4
+ data.tar.gz: e2ef640c6126fa551258c29bafca19bdeb92ff0c
5
5
  SHA512:
6
- metadata.gz: 0a57f9f297cf8c2b77e7d49185991dc154bb7dc0968a0c220ea666d84306bb10a6fc07f8ece5593b3776deae3f356ed857475ac314dfc1fa5b5aea616e7c64ee
7
- data.tar.gz: a76705582cda894101104c34d73ab0c7dcec1b15557302c5ed753fce3746ccacc27de7151a29855351abcb0411406f841c84244fd53ad322320e532e6f446a31
6
+ metadata.gz: fbb6dea46c1245ae3e471f67ae62b75d5ce20937dba2c06fd82671e6ebad78f8fbe136816bbc7afc902f18d9aedbb98a9547a13792e167d5e791b6bfd36c12e9
7
+ data.tar.gz: 4ff9e33ab4b1cdc1969c547e8ba56733e9b406876409568d1ced9ee8b54d70ade58e456e66064f6055a8f6b0b818157308924de9060d83b1a807ed7d6d126f0e
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![Teapot](teapot.png)
4
4
 
5
- Samovar is a modern framework for building command-line tools and applications. It provides a declarative class-based DSL for building command-line parsers that include automatic documentation generation `--help`. It helps you keep your functionality clean and isolated where possible.
5
+ Samovar is a modern framework for building command-line tools and applications. It provides a declarative class-based DSL for building command-line parsers that include automatic documentation generation. It helps you keep your functionality clean and isolated where possible.
6
6
 
7
7
  [![Build Status](https://secure.travis-ci.org/ioquatix/samovar.svg)](http://travis-ci.org/ioquatix/samovar)
8
8
  [![Code Climate](https://codeclimate.com/github/ioquatix/samovar.svg)](https://codeclimate.com/github/ioquatix/samovar)
@@ -14,6 +14,12 @@ I've been using [Trollop](https://github.com/ManageIQ/trollop) and while it's no
14
14
 
15
15
  One of the other issues I had with existing frameworks is testability. Most frameworks expect to have some pretty heavy logic directly in the binary executable, or at least don't structure your code in a way which makes testing easy. Samovar structures your command processing logic into classes which can be easily tested in isolation, which means that you can mock up and [spec your command-line executables easily](https://github.com/ioquatix/teapot/blob/master/spec/teapot/command_spec.rb).
16
16
 
17
+ ## Examples
18
+
19
+ - [Teapot](https://github.com/ioquatix/teapot/blob/master/lib/teapot/command.rb) is a build system and uses multiple top-level commands.
20
+ - [Utopia](https://github.com/ioquatix/utopia/blob/master/lib/utopia/command.rb) is a web application platform and uses nested commands.
21
+ - [LSync](https://github.com/ioquatix/lsync/blob/master/lib/lsync/command.rb) is a backup tool and sends commands across the network and has lots of options with default values.
22
+
17
23
  ## Installation
18
24
 
19
25
  Add this line to your application's Gemfile:
@@ -30,11 +36,79 @@ Or install it yourself as:
30
36
 
31
37
  ## Usage
32
38
 
33
- The best example of a working Samovar command line is probably [Teapot](https://github.com/ioquatix/teapot/blob/master/lib/teapot/command.rb).
34
-
35
- [Utopia](https://github.com/ioquatix/utopia/blob/master/lib/utopia/command.rb) shows how to use multiple levels of nested commands.
36
-
37
- Please feel free to submit other examples and I will link to them here.
39
+ ### Basic Options
40
+
41
+ require 'samovar'
42
+
43
+ class Application < Samovar::Command
44
+ options do
45
+ option '-f/--frobulate <text>', "Frobulate the text"
46
+ option '-x | -y', "Specify either x or y axis.", key: :axis
47
+ option '-F/--yeah/--flag', "A boolean flag with several forms."
48
+ end
49
+ end
50
+
51
+ application = Application.new(['-f', 'Algebraic!'])
52
+ application.options[:frobulate] # 'Algebraic!'
53
+
54
+ application = Application.new(['-x', '-y'])
55
+ application.options[:axis] # :y
56
+
57
+ application = Application.new(['-F'])
58
+ application.options[:flag] # true
59
+
60
+ ### Nested Commands
61
+
62
+ require 'samovar'
63
+
64
+ class Create < Samovar::Command
65
+ def invoke(parent)
66
+ puts "Creating"
67
+ end
68
+ end
69
+
70
+ class Application < Samovar::Command
71
+ nested '<command>',
72
+ 'create' => Create
73
+
74
+ def invoke(program_name: File.basename($0))
75
+ if @command
76
+ @command.invoke
77
+ else
78
+ print_usage(program_name)
79
+ end
80
+ end
81
+ end
82
+
83
+ Application.new(['create']).invoke
84
+
85
+ ### ARGV Splits
86
+
87
+ require 'samovar'
88
+
89
+ class Application < Samovar::Command
90
+ many :packages
91
+ split :argv
92
+ end
93
+
94
+ application = Application.new(['foo', 'bar', 'baz', '--', 'apples', 'oranges', 'feijoas'])
95
+ application.packages # ['foo', 'bar', 'baz']
96
+ application.argv # ['apples', 'oranges', 'feijoas']
97
+
98
+ ### Parsing Tokens
99
+
100
+ require 'samovar'
101
+
102
+ class Application < Samovar::Command
103
+ self.description = "Mix together your favorite things."
104
+
105
+ one :fruit, "Name one fruit"
106
+ many :cakes, "Any cakes you like"
107
+ end
108
+
109
+ application = Application.new(['apple', 'chocolate cake', 'fruit cake'])
110
+ application.fruit # 'apple'
111
+ application.cakes # ['chocolate cake', 'fruit cake']
38
112
 
39
113
  ## Contributing
40
114
 
@@ -46,7 +120,39 @@ Please feel free to submit other examples and I will link to them here.
46
120
 
47
121
  ### Future Work
48
122
 
49
- One area that I'd like to work on is line-wrapping. Right now, line wrapping is done by the terminal which is a bit ugly in some cases. There is a [half-implemented elegant solution](lib/samovar/output/line_wrapper.rb).
123
+ #### Line Wrapping
124
+
125
+ Line wrapping is done by the terminal which is a bit ugly in some cases. There is a [half-implemented elegant solution](lib/samovar/output/line_wrapper.rb).
126
+
127
+ #### Type Coercion
128
+
129
+ It might make sense to enforce constraints at parse time.. or not. For example, if an option is given like `--count <int>` we should probably parse an integer?
130
+
131
+ #### Multi-value Options
132
+
133
+ Right now, options can take a single argument, e.g. `--count <int>`. Ideally, we support a specific sub-parser defined by the option, e.g. `--count <int...>` or `--tag <section> <tags...>`. These would map to specific parsers using `Samovar::One` and `Samovar::Many` internally.
134
+
135
+ #### Global Options
136
+
137
+ Options can only be parsed at the place they are explicitly mentioned, e.g. a command with sub-commands won't parse an option added to the end of the command:
138
+
139
+ command list --help
140
+
141
+ One might reasonably expect this to parse but it isn't so easy to generalize this:
142
+
143
+ command list -- --help
144
+
145
+ In this case, do we show help? Some effort is required to disambiguate this. Initially, it makes sense to keep things as simple as possible. But, it might make sense for some options to be declared in a global scope, which are extracted before parsing begins. I'm not sure if this is really a good idea. It might just be better to give good error output in this case (you specified an option but it was in the wrong place).
146
+
147
+ #### Shell Auto-completion
148
+
149
+ Because of the structure of the Samovar command parser, it should be possible to generate a list of all possible tokens at each point. Therefore, semantically correct tab completion should be possible.
150
+
151
+ As a secondary to this, it would be nice if `Samovar::One` and `Samovar::Many` could take a list of potential tokens so that auto-completion could give meaningful suggestions, and possibly improved validation.
152
+
153
+ #### Short/Long Help
154
+
155
+ It might be interesting to explore whether it's possible to have `-h` and `--help` do different things. This could include command specific help output, more detailed help output (similar to a man page), and other useful help related tasks.
50
156
 
51
157
  ## License
52
158
 
@@ -42,6 +42,8 @@ module Samovar
42
42
  attr :description
43
43
  attr :type
44
44
 
45
+ attr :default
46
+
45
47
  attr :key
46
48
 
47
49
  def parse(input)
@@ -77,11 +79,17 @@ module Samovar
77
79
  def initialize(title = "Options", key: :options)
78
80
  @title = title
79
81
  @ordered = []
82
+
83
+ # We use this flag to option cache to improve parsing performance:
80
84
  @keyed = {}
85
+
81
86
  @key = key
87
+
88
+ @defaults = {}
82
89
  end
83
90
 
84
91
  attr :key
92
+ attr :defaults
85
93
 
86
94
  def option(*args, **options)
87
95
  self << Option.new(*args, **options)
@@ -96,10 +104,14 @@ module Samovar
96
104
  @keyed[alternative] = option
97
105
  end
98
106
  end
107
+
108
+ if default = option.default
109
+ @defaults[option.key] = option.default
110
+ end
99
111
  end
100
112
 
101
113
  def parse(input)
102
- values = Hash.new
114
+ values = @defaults.dup
103
115
 
104
116
  while option = @keyed[input.first]
105
117
  if result = option.parse(input)
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Samovar
22
- VERSION = "1.1.0"
22
+ VERSION = "1.1.1"
23
23
  end
@@ -15,7 +15,7 @@ module Command
15
15
  self.description = "A decentralised package manager and build tool."
16
16
 
17
17
  options do
18
- option '-c/--configuration <name>', "Specify a specific build configuration.", default: ENV['TEAPOT_CONFIGURATION']
18
+ option '-c/--configuration <name>', "Specify a specific build configuration.", default: 'TEAPOT_CONFIGURATION'
19
19
  option '-i/--in/--root <path>', "Work in the given root directory."
20
20
  option '--verbose | --quiet', "Verbosity of output for debugging.", key: :logging
21
21
  option '-h/--help', "Print out help information."
@@ -28,6 +28,11 @@ module Command
28
28
  end
29
29
 
30
30
  describe Samovar::Command do
31
+ it "should use default value" do
32
+ top = Command::Top.parse([])
33
+ expect(top.options[:configuration]).to be == 'TEAPOT_CONFIGURATION'
34
+ end
35
+
31
36
  it "should parse a simple command" do
32
37
  top = Command::Top.parse(["-c", "path", "bottom", "foobar", "A", "B", "--", "args", "args"])
33
38
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: samovar
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-24 00:00:00.000000000 Z
11
+ date: 2016-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mapping