cli-mastermind 0.5.1 → 0.6.0

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
  SHA256:
3
- metadata.gz: 14bea90e61e0acaf588c50485fc37947c376b5778d9a7e8752b948a540d94f44
4
- data.tar.gz: cdd0b63de45746a2b5df33e72245b20037adcf89665bb98c2c5200f58de2c3c1
3
+ metadata.gz: 9078a8e331150ebe62b1ecf44270422c93855b869510f34d57e983895a3b7fcf
4
+ data.tar.gz: c7bb2f6a630aa6b62319e409f238b88a1a81a4baa3a8e76737b1290e15efd2fc
5
5
  SHA512:
6
- metadata.gz: 29adefa5c6f7a489071af7c726671788b8a3d38b37c4d7af5d53cd24346bc9a2a319fb5fd526734902182d9c06dfa0fae3550d7514cc9e51b534d20b775be03d
7
- data.tar.gz: cafc5940e66d5a756251aa09ec43cc1cb141111eb59be05d145f909db6f3c6a50b391aaf3315abce85ac757ae713ab298e51f47e002bf8c66f3341a4f65460bb
6
+ metadata.gz: 1ec54b9f8e61defa6dd76c40cdd6d46fbba1afb6e173e47f25e0042ed69b7ca4ae32d4dd75ca924af55c22f4a10e2f4f22d2ab907f71abac789e9b08248ed7f9
7
+ data.tar.gz: ef03260db00aa0062ed9514ae5bd6e201274d89778dccafa1f74b94c1bf2566665513e4ae4fd638b1c717e1586990275d3c4786a3952b721d6bd74849c3a4554
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ require 'forwardable'
2
3
  require 'cli/ui'
3
4
  require 'cli/mastermind/arg_parse'
4
5
  require 'cli/mastermind/configuration'
@@ -104,34 +105,44 @@ module CLI
104
105
 
105
106
  unless @plans.empty?
106
107
  frame('Plans') do
107
- display_plans
108
+ puts build_display_string
108
109
  end
109
110
  else
110
111
  puts stylize("{{x}} No plans match #{@arguments.pattern.source}")
111
112
  end
112
113
  end
113
114
 
114
- def display_plans(plans=@plans, prefix='')
115
+ def build_display_string(plans=@plans, prefix='')
115
116
  fade_code = CLI::UI::Color.new(90, '').code
117
+ reset = CLI::UI::Color::RESET.code
118
+
119
+ display_string = ''
116
120
 
117
121
  plans.each do |(name, plan)|
118
122
  next unless plan.has_children? or plan.description
119
123
 
120
- print prefix + '• '
121
- puts stylize("{{yellow:#{titleize(name)} #{fade_code}(#{name})#{CLI::UI::Color::RESET.code}")
124
+ display_string += prefix + '• '
125
+ display_string += stylize("{{yellow:#{titleize(name)} #{fade_code}(#{name})#{reset}\n")
122
126
 
123
127
  if plan.aliases.any?
124
- puts prefix + " - #{fade_code}aliases: #{plan.aliases.to_a.join(', ')}#{CLI::UI::Color::RESET.code}"
128
+ display_string += prefix + " - #{fade_code}aliases: #{plan.aliases.to_a.join(', ')}#{reset}\n"
125
129
  end
126
130
 
127
131
  if plan.description
128
- print prefix + ' - '
129
- puts stylize("{{blue:#{plan.description}}}")
132
+ display_string += prefix + ' - '
133
+ display_string += stylize("{{blue:#{plan.description}}}\n")
130
134
  end
131
135
 
132
- display_plans(plan.children, " " + prefix) if plan.has_children?
133
- print "\n"
136
+ if plan.has_children?
137
+ display_string += "\n"
138
+ display_string += build_display_string(plan.children, " " + prefix)
139
+ end
140
+
141
+ display_string += "\n"
134
142
  end
143
+
144
+ # Collapse any run of three or more newlines into just two
145
+ display_string.gsub(/\n{3,}/, "\n\n")
135
146
  end
136
147
 
137
148
  def filter_plans(pattern, plans=@plans)
@@ -15,6 +15,8 @@ module CLI
15
15
  # _last_. You can use this to specify plans you want accessible everywhere
16
16
  # or global configuration that should apply everywhere (unless overridden by
17
17
  # more specific masterplans).
18
+ #
19
+ # @see Configuration::DSL
18
20
  class Configuration
19
21
  # Filename of masterplan files
20
22
  PLANFILE = '.masterplan'
@@ -144,6 +146,10 @@ module CLI
144
146
  end
145
147
  end
146
148
 
149
+ # Describes the DSL used in masterplan files.
150
+ #
151
+ # See the .masterplan file in the root of this repo for a full example of
152
+ # the available options.
147
153
  class DSL
148
154
  def initialize(config, filename)
149
155
  @config = config
@@ -154,26 +160,48 @@ module CLI
154
160
  # Specifies that another masterplan should also be loaded when loading
155
161
  # this masterplan. NOTE: This _immediately_ loads the other masterplan.
156
162
  def see_also(filename)
157
- @config.load_masterplan(filename)
163
+ @config.load_masterplan(File.expand_path(filename))
158
164
  end
159
165
 
160
- # With no arguments, specifies that the current directory containing this
161
- # masterplan is at the root of your project. Otherwise, specifies the root
162
- # of the project.
163
- def project_root(root = File.dirname(@filename))
166
+ # Specifies the root of the project.
167
+ # +root+ must be a directory.
168
+ def project_root(root)
169
+ unless Dir.exist? root
170
+ raise InvalidDirectoryError.new('Invalid project root', root)
171
+ end
172
+
164
173
  @config.project_root = root
165
174
  end
166
- alias_method :at_project_root, :project_root
167
175
 
168
- # With no arguments, specifies that plans exist in a /plans/ directory
169
- # under the directory the masterplan is in.
170
- def plan_files(directory = File.join(File.dirname(@filename), 'plans'))
171
- @config.add_plans(Dir.glob(File.join(directory, '**', "*{#{supported_extensions}}")))
176
+ # Syntactic sugar on top of `project_root` to specify that the current
177
+ # masterplan resides in the root of the project.
178
+ def at_project_root
179
+ project_root File.dirname(@filename)
180
+ end
181
+
182
+ # Specify that plans exist in the given +directory+.
183
+ # Must be a valid directory
184
+ def plan_files(directory)
185
+ unless Dir.exist? directory
186
+ raise InvalidDirectoryError.new('Invalid plan file directory', directory)
187
+ end
188
+
189
+ planfiles = Dir.glob(File.join(directory, '**', "*{#{supported_extensions}}"))
190
+ planfiles.map! { |file| File.expand_path(file) }
191
+
192
+ @config.add_plans(planfiles)
193
+ end
194
+
195
+ # Syntactic sugar on top of `plan_files` to specify that plans exist in
196
+ # a +plans/+ directory in the current directory.
197
+ def has_plan_files
198
+ plan_files File.join(File.dirname(@filename), 'plans')
172
199
  end
173
- alias_method :has_plan_files, :plan_files
174
200
 
175
201
  # Specifies that a specific plan file exists at the given +filename+.
176
202
  def plan_file(*files)
203
+ files = files.map { |file| File.expand_path file }
204
+
177
205
  @config.add_plans(files)
178
206
  end
179
207
 
@@ -11,5 +11,11 @@ module CLI
11
11
 
12
12
  class InvalidPlanError < Error
13
13
  end
14
+
15
+ class InvalidDirectoryError < Error
16
+ def initialize(message, directory)
17
+ super "#{message}: #{directory} does not exist or is not a directory"
18
+ end
19
+ end
14
20
  end
15
21
  end
@@ -13,6 +13,8 @@ module CLI::Mastermind
13
13
  private
14
14
 
15
15
  class DSL
16
+ extend Forwardable
17
+
16
18
  attr_reader :plans
17
19
 
18
20
  def initialize(filename=nil, &block)
@@ -50,6 +52,12 @@ module CLI::Mastermind
50
52
  def set_alias(alias_to)
51
53
  @plans.last.add_alias(alias_to)
52
54
  end
55
+
56
+ # Delegate configuration to the top-level configuration object
57
+ # Planfile loading happens well after configuration has been loaded. So,
58
+ # we can safely rely on it being setup at this point.
59
+ def_delegator :'CLI::Mastermind', :configuration
60
+ alias_method :config, :configuration
53
61
  end
54
62
  end
55
63
  end
@@ -1,4 +1,3 @@
1
- require 'forwardable'
2
1
  require 'cli/mastermind/plan/interface'
3
2
 
4
3
  module CLI
@@ -7,8 +7,8 @@ module CLI
7
7
 
8
8
  module VERSION
9
9
  RELEASE = 0
10
- MAJOR = 5
11
- MINOR = 1
10
+ MAJOR = 6
11
+ MINOR = 0
12
12
  PATCH = nil
13
13
 
14
14
  STRING = [RELEASE, MAJOR, MINOR, PATCH].compact.join('.').freeze
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cli-mastermind
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Hall
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-06 00:00:00.000000000 Z
11
+ date: 2019-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cli-ui