bake 0.12.1 → 0.13.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5451e66cf2062b167b8b9983bb0308612b6234de8f99af360ddb1098e74d973e
4
- data.tar.gz: feb9f86818d18175eab079b7875c3b3810d1017dcb82f717aaab2f02d04d44ed
3
+ metadata.gz: e4138c750ccdded2e0b36d082d94fecc0ae4afd0cfda6bad6e47179e37450f47
4
+ data.tar.gz: 236deaa42f0a148e195abdbeca1a8298e252ee335ea5cbceddc97e5c06dce195
5
5
  SHA512:
6
- metadata.gz: 6043f4715eafdb780fea3c09ad50fe262d3e2a80234c4c76884b887bf0460e96f652bca576f5f5215d1d0aada420f33a0c8894fbc45ef2b10e716a075890e97c
7
- data.tar.gz: dd58f182d931c1844d5b50794e55d0dd4ec5933fa201e2206adb6abf879b2aff19ab6030c0b2035186e748d5ef1070c34c518573d5fc3c4b7c8f679687ffe5af
6
+ metadata.gz: 0b249b795b9f91489d0150a5d511d3d22a6d4d2292fba3f2680455a2831c9b3480abed70d107127bf45cf76d5197395b9c9be597902800c39ca95be6e761ade8
7
+ data.tar.gz: ec9e06a913c3f457b227d077ae7d2e0f19d90ac7a417edcb3f1d721c0d6176dd62a178d5b6e2db5ff66084e60fda446af5c9f0ee013da98435fc15287e2f0726
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Bake is a task execution tool, inspired by Rake, but codifying many of the use cases which are typically implemented in an ad-hoc manner.
4
4
 
5
- [![Actions Status](https://github.com/ioquatix/bake/workflows/Development/badge.svg)](https://github.com/ioquatix/bake/actions?workflow=Development)
5
+ [![Development](https://github.com/ioquatix/bake/workflows/Development/badge.svg)](https://github.com/ioquatix/bake/actions?workflow=Development)
6
6
 
7
7
  ## Motivation
8
8
 
@@ -23,81 +23,7 @@ Execute the following in your project:
23
23
 
24
24
  ## Usage
25
25
 
26
- Bake follows similar patterns to Rake.
27
-
28
- ![Example](example.png)
29
-
30
- ## Bakefile
31
-
32
- There is a root level `bake.rb` e.g.:
33
-
34
- ```ruby
35
- def cake
36
- ingredients = call 'supermarket:shop', 'flour,sugar,cocoa'
37
- lookup('mixer:add').call(ingredients)
38
- end
39
- ```
40
-
41
- This file is project specific and is the only file which can expose top level tasks (i.e. without a defined namespace). When used in a gem, these tasks are not exposed to other gems/projects.
42
-
43
- ## Recipes
44
-
45
- Alongside the `bake.rb`, there is a `bake/` directory which contains files like `supermarket.rb`. These files contain recipes, e.g.:
46
-
47
- ```ruby
48
- # @param ingredients [Array(Any)] the ingredients to purchase.
49
- def shop(ingredients)
50
- supermarket = Supermarket.best
51
-
52
- return supermarket.purchase(ingredients)
53
- end
54
- ```
55
-
56
- These methods are automatically scoped according to the file name, e.g. `bake/supermarket.rb` will define `supermarket:shop`.
57
-
58
- ## Gems
59
-
60
- Adding a `bake/` directory to your gem will allow other gems and projects to consume those recipes. In order to prevent collisions, you *should* prefix your commands with the name of the gem, e.g. in `mygem/bake/mygem.rb`:
61
-
62
- ```ruby
63
- def setup
64
- # ...
65
- end
66
- ```
67
-
68
- Then, in your project `myproject` which depends on `mygem`:
69
-
70
- ```
71
- bake mygem:setup
72
- ```
73
-
74
- ## Arguments
75
-
76
- Arguments work as normal. Documented types are used to parse strings from the command line. Both positional and optional parameters are supported.
77
-
78
- ### Positional Parameters
79
-
80
- ```ruby
81
- # @param x [Integer]
82
- # @param y [Integer]
83
- def add(x, y)
84
- puts x + y
85
- end
86
- ```
87
-
88
- Which is invoked by `bake add 1 2`.
89
-
90
- ### Optional Parameters
91
-
92
- ```ruby
93
- # @param x [Integer]
94
- # @param y [Integer]
95
- def add(x:, y:)
96
- puts x + y
97
- end
98
- ```
99
-
100
- Which is invoked by `bake add x=1 y=2`.
26
+ Please see the <a href="https://ioquatix.github.io/bake/">project documentation</a> or run it locally using `bake utopia:project:serve`.
101
27
 
102
28
  ## Contributing
103
29
 
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.metadata["donation_uri"] = "https://github.com/sponsors/ioquatix"
15
15
 
16
16
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(docs|test|spec|features)/}) }
18
18
  end
19
19
 
20
20
  spec.bindir = "bin"
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_development_dependency 'bake-bundler'
27
27
 
28
+ spec.add_development_dependency 'utopia-project'
28
29
  spec.add_development_dependency 'covered'
29
30
  spec.add_development_dependency 'bundler'
30
31
  spec.add_development_dependency 'rspec'
data/gems.rb CHANGED
@@ -2,4 +2,3 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in bake.gemspec
4
4
  gemspec
5
-
@@ -0,0 +1,55 @@
1
+ # Command Line Interface
2
+
3
+ The `bake` command is broken up into two main functions: `list` and `call`.
4
+
5
+ <pre>% bake --help
6
+ <b>bake [-h/--help] [-b/--bakefile &lt;path&gt;] &lt;command&gt;</b>
7
+ <font color="#638FFF">Execute tasks using Ruby.</font>
8
+
9
+ [-h/--help] Show help.
10
+ [-b/--bakefile &lt;path&gt;] Override the path to the bakefile to use.
11
+ &lt;command&gt; One of: call, list. (default: call)
12
+
13
+ <b>call &lt;commands...&gt;</b>
14
+ <font color="#638FFF">Execute one or more commands.</font>
15
+
16
+ &lt;commands...&gt; The commands &amp; arguments to invoke. (default: [&quot;default&quot;])
17
+
18
+ <b>list &lt;pattern&gt;</b>
19
+ &lt;pattern&gt; The pattern to filter tasks by.
20
+ </pre>
21
+
22
+ ## List
23
+
24
+ The `bake list` command allows you to list all available recipes. By proving a pattern you will only see recipes that have a matching command name.
25
+
26
+ <pre>$ bake list console
27
+ <b>Bake::Loader console-1.8.2</b>
28
+
29
+ <b>console:info</b>
30
+ <font color="#638FFF">Increase the verbosity of the logger to info.</font>
31
+
32
+ <b>console:debug</b>
33
+ <font color="#638FFF">Increase the verbosity of the logger to debug.</font>
34
+ </pre>
35
+
36
+ The listing documents positional and optional arguments. The documentation is generated from the comments in the bakefiles.
37
+
38
+ ## Call
39
+
40
+ The `bake call` (the default, so `call` can be omitted) allows you to execute one or more recipes. You must provide the name of the command, followed by any arguments.
41
+
42
+ <pre>$ bake async:http:head https://www.codeotaku.com/index
43
+ <font color="#638FFF"><b> HEAD</b></font>: https://www.codeotaku.com/index
44
+ <font color="#00AA00"><b> version</b></font>: h2
45
+ <font color="#00AA00"><b> status</b></font>: 200
46
+ <font color="#00AA00"><b> body</b></font>: body with length <b>7879B</b>
47
+ <b> content-type</b>: &quot;text/html; charset=utf-8&quot;
48
+ <b> cache-control</b>: &quot;public, max-age=3600&quot;
49
+ <b> expires</b>: &quot;Mon, 04 May 2020 13:23:47 GMT&quot;
50
+ <b> server</b>: &quot;falcon/0.36.4&quot;
51
+ <b> date</b>: &quot;Mon, 04 May 2020 12:23:47 GMT&quot;
52
+ <b> vary</b>: &quot;accept-encoding&quot;
53
+ </pre>
54
+
55
+ You can specify multiple commands and they will be executed sequentially.
@@ -0,0 +1,69 @@
1
+ # Gem Integration
2
+
3
+ This guide explains how to add `bake` to a Ruby gem and export standardised tasks for use by other gems and projects.
4
+
5
+ ## Exporting Tasks
6
+
7
+ Adding a `bake/` directory to your gem will allow other gems and projects to consume those recipes. In order to prevent collisions, you *should* prefix your commands with the name of the gem, e.g. in `mygem/bake/mygem.rb`:
8
+
9
+ ~~~ ruby
10
+ def setup
11
+ # ...
12
+ end
13
+ ~~~
14
+
15
+ Then, in a different project which depends on `mygem`, you can run tasks from `mygem` by invoking them using `bake`:
16
+
17
+ ~~~ bash
18
+ $ bake mygem:setup
19
+ ~~~
20
+
21
+ ## Examples
22
+
23
+ There are many gems which export tasks in this way. Here are some notable examples:
24
+
25
+ ### Variant
26
+
27
+ The [variant gem](https://github.com/socketry/variant) exposes bake tasks for setting the environment e.g. `development`, `testing`, or `production`.
28
+
29
+ <pre class="terminal">$ bake list variant
30
+ <b>Bake::Loader variant-0.1.1</b>
31
+
32
+ <b>variant:production</b> <font color="#00AA00">**overrides</font>
33
+ <font color="#638FFF">Select the production variant.</font>
34
+ <font color="#00AA00">overrides</font> [Hash] <font color="#638FFF">any specific variant overrides.</font>
35
+
36
+ <b>variant:staging</b> <font color="#00AA00">**overrides</font>
37
+ <font color="#638FFF">Select the staging variant.</font>
38
+ <font color="#00AA00">overrides</font> [Hash] <font color="#638FFF">any specific variant overrides.</font>
39
+
40
+ <b>variant:development</b> <font color="#00AA00">**overrides</font>
41
+ <font color="#638FFF">Select the development variant.</font>
42
+ <font color="#00AA00">overrides</font> [Hash] <font color="#638FFF">any specific variant overrides.</font>
43
+
44
+ <b>variant:testing</b> <font color="#00AA00">**overrides</font>
45
+ <font color="#638FFF">Select the testing variant.</font>
46
+ <font color="#00AA00">overrides</font> [Hash] <font color="#638FFF">any specific variant overrides.</font>
47
+
48
+ <b>variant:force</b> <font color="#AA0000">name</font> <font color="#00AA00">**overrides</font>
49
+ <font color="#638FFF">Force a specific variant.</font>
50
+ <font color="#00AA00">name</font> [Symbol] <font color="#638FFF">the default variant.</font>
51
+ <font color="#00AA00">overrides</font> [Hash] <font color="#638FFF">any specific variant overrides.</font>
52
+
53
+ <b>variant:show</b>
54
+ <font color="#638FFF">Show variant-related environment variables.</font>
55
+ </pre>
56
+
57
+ ### Console
58
+
59
+ The [console gem](https://github.com/socketry/console) exposes bake tasks to change the log level.
60
+
61
+ <pre class="terminal">$ bake list console
62
+ <b>Bake::Loader console-1.8.2</b>
63
+
64
+ <b>console:info</b>
65
+ <font color="#638FFF">Increase the verbosity of the logger to info.</font>
66
+
67
+ <b>console:debug</b>
68
+ <font color="#638FFF">Increase the verbosity of the logger to debug.</font>
69
+ </pre>
@@ -0,0 +1,64 @@
1
+ # Project Integration
2
+
3
+ This guide explains how to add `bake` to a Ruby project.
4
+
5
+ ## Bakefile
6
+
7
+ At the top level of your project, you can create a `bake.rb` file, which contains top level tasks which are private to your project.
8
+
9
+ ~~~ ruby
10
+ def cake
11
+ ingredients = call 'supermarket:shop', 'flour,sugar,cocoa'
12
+ lookup('mixer:add').call(ingredients)
13
+ end
14
+ ~~~
15
+
16
+ This file is project specific and is the only file which can expose top level tasks (i.e. without a defined namespace). When used in a gem, these tasks are not exposed to other gems/projects.
17
+
18
+ ## Recipes
19
+
20
+ Alongside the `bake.rb`, there is a `bake/` directory which contains files like `supermarket.rb`. These files contain recipes, e.g.:
21
+
22
+ ~~~ ruby
23
+ # @param ingredients [Array(Any)] the ingredients to purchase.
24
+ def shop(ingredients)
25
+ supermarket = Supermarket.best
26
+
27
+ return supermarket.purchase(ingredients)
28
+ end
29
+ ~~~
30
+
31
+ These methods are automatically scoped according to the file name, e.g. `bake/supermarket.rb` will define `supermarket:shop`.
32
+
33
+
34
+ ## Arguments
35
+
36
+ Arguments work as normal. Documented types are used to parse strings from the command line. Both positional and optional parameters are supported.
37
+
38
+ ### Positional Parameters
39
+
40
+ Positional parameters are non-keyword parameters which may have a default value. However, because of the limits of the command line, all positional arguments must be specified.
41
+
42
+ ~~~ ruby
43
+ # @param x [Integer]
44
+ # @param y [Integer]
45
+ def add(x, y)
46
+ puts x + y
47
+ end
48
+ ~~~
49
+
50
+ Which is invoked by `bake add 1 2`.
51
+
52
+ ### Optional Parameters
53
+
54
+ Optional parameters are keyword parameters which may have a default value. The parameter is set on the command line using the name of the parameter followed by an equals sign, followed by the value.
55
+
56
+ ~~~ ruby
57
+ # @param x [Integer]
58
+ # @param y [Integer]
59
+ def add(x:, y: 2)
60
+ puts x + y
61
+ end
62
+ ~~~
63
+
64
+ Which is invoked by `bake add x=1`. Because `y` is not specified, it will default to `2` as per the method definition.
@@ -22,7 +22,10 @@ require_relative 'recipe'
22
22
  require_relative 'scope'
23
23
 
24
24
  module Bake
25
+ # The base class for including {Scope} instances which define {Recipe} instances.
25
26
  class Base < Struct.new(:context)
27
+ # Generate a base class for the specified path.
28
+ # @param path [Array(String)] The command path.
26
29
  def self.derive(path = [])
27
30
  klass = Class.new(self)
28
31
 
@@ -31,6 +34,8 @@ module Bake
31
34
  return klass
32
35
  end
33
36
 
37
+ # Format the class as a command.
38
+ # @return [String]
34
39
  def self.to_s
35
40
  if path = self.path
36
41
  path.join(':')
@@ -47,20 +52,31 @@ module Bake
47
52
  end
48
53
  end
49
54
 
55
+ # The path of this derived base class.
56
+ # @return [Array(String)]
50
57
  def self.path
51
58
  self.const_get(:PATH)
52
59
  rescue
53
60
  nil
54
61
  end
55
62
 
63
+ # The path for this derived base class.
64
+ # @return [Array(String)]
56
65
  def path
57
66
  self.class.path
58
67
  end
59
68
 
69
+ # Proxy a method call using command line arguments through to the {Context} instance.
70
+ # @param arguments [Array(String)]
60
71
  def call(*arguments)
61
72
  self.context.call(*arguments)
62
73
  end
63
74
 
75
+ # Recipes defined in this scope.
76
+ #
77
+ # @block `{|recipe| ...}`
78
+ # @yield recipe [Recipe]
79
+ # @return [Enumerable]
64
80
  def recipes
65
81
  return to_enum(:recipes) unless block_given?
66
82
 
@@ -71,6 +87,9 @@ module Bake
71
87
  end
72
88
  end
73
89
 
90
+ # Look up a recipe with a specific name.
91
+ #
92
+ # @param name [String] The instance method to look up.
74
93
  def recipe_for(name)
75
94
  Recipe.new(self, name)
76
95
  end
@@ -21,6 +21,7 @@
21
21
  require_relative 'command/top'
22
22
 
23
23
  module Bake
24
+ # The command line interface.
24
25
  module Command
25
26
  def self.call(*arguments)
26
27
  Top.call(*arguments)
@@ -26,6 +26,7 @@ require_relative '../context'
26
26
 
27
27
  module Bake
28
28
  module Command
29
+ # Execute one or more commands.
29
30
  class Call < Samovar::Command
30
31
  self.description = "Execute one or more commands."
31
32
 
@@ -23,7 +23,10 @@ require 'set'
23
23
 
24
24
  module Bake
25
25
  module Command
26
+ # List all available commands.
26
27
  class List < Samovar::Command
28
+ self.description = "List all available commands."
29
+
27
30
  one :pattern, "The pattern to filter tasks by."
28
31
 
29
32
  def format_parameters(parameters, terminal)
@@ -26,6 +26,7 @@ require_relative 'list'
26
26
 
27
27
  module Bake
28
28
  module Command
29
+ # The top level command line application.
29
30
  class Top < Samovar::Command
30
31
  self.description = "Execute tasks using Ruby."
31
32
 
@@ -56,12 +57,12 @@ module Bake
56
57
  return terminal
57
58
  end
58
59
 
59
- def bakefile
60
+ def bakefile_path
60
61
  @options[:bakefile] || Dir.pwd
61
62
  end
62
63
 
63
64
  def context
64
- Context.load(self.bakefile)
65
+ Context.load(self.bakefile_path)
65
66
  end
66
67
 
67
68
  def call
@@ -21,11 +21,14 @@
21
21
  require_relative 'base'
22
22
 
23
23
  module Bake
24
+ # The default file name for the top level bakefile.
24
25
  BAKEFILE = "bake.rb"
25
26
 
27
+ # Represents a context of task execution, containing all relevant state.
26
28
  class Context
29
+ # Search upwards from the specified path for a {BAKEFILE}.
27
30
  # If path points to a file, assume it's a `bake.rb` file. Otherwise, recursively search up the directory tree starting from `path` to find the specified bakefile.
28
- # @return [String, nil] the path to the bakefile if it could be found.
31
+ # @return [String | Nil] The path to the bakefile if it could be found.
29
32
  def self.bakefile_path(path, bakefile: BAKEFILE)
30
33
  if File.file?(path)
31
34
  return path
@@ -52,6 +55,8 @@ module Bake
52
55
  return nil
53
56
  end
54
57
 
58
+ # Load a context from the specified path.
59
+ # @path [String] A file-system path.
55
60
  def self.load(path = Dir.pwd)
56
61
  if bakefile_path = self.bakefile_path(path)
57
62
  scope = Scope.load(bakefile_path)
@@ -68,6 +73,8 @@ module Bake
68
73
  return self.new(loaders, scope, working_directory)
69
74
  end
70
75
 
76
+ # Initialize the context with the specified loaders.
77
+ # @param loaders [Loaders]
71
78
  def initialize(loaders, scope = nil, root = nil)
72
79
  @loaders = loaders
73
80
 
@@ -92,10 +99,18 @@ module Bake
92
99
  end
93
100
  end
94
101
 
102
+ # The loaders which will be used to resolve recipes in this context.
103
+ attr :loaders
104
+
105
+ # The scope for the root {BAKEFILE}.
95
106
  attr :scope
107
+
108
+ # The root path of this context.
109
+ # @return [String | Nil]
96
110
  attr :root
97
- attr :loaders
98
111
 
112
+ # Invoke recipes on the context using command line arguments.
113
+ # @param commands [Array(String)]
99
114
  def call(*commands)
100
115
  last_result = nil
101
116
 
@@ -111,6 +126,8 @@ module Bake
111
126
  return last_result
112
127
  end
113
128
 
129
+ # Lookup a recipe for the given command name.
130
+ # @param command [String] The command name, e.g. `bundler:release`.
114
131
  def lookup(command)
115
132
  @recipes[command]
116
133
  end
@@ -21,14 +21,21 @@
21
21
  require_relative 'scope'
22
22
 
23
23
  module Bake
24
+ # Structured access to a set of comment lines.
24
25
  class Documentation
25
-
26
+ # Initialize the documentation with an array of comments.
27
+ #
28
+ # @param comments [Array(String)] An array of comment lines.
26
29
  def initialize(comments)
27
30
  @comments = comments
28
31
  end
29
32
 
30
33
  DESCRIPTION = /\A\s*([^@\s].*)?\z/
31
34
 
35
+ # The text-only lines of the comment block.
36
+ #
37
+ # @yield [String]
38
+ # @return [Enumerable]
32
39
  def description
33
40
  return to_enum(:description) unless block_given?
34
41
 
@@ -55,6 +62,11 @@ module Bake
55
62
 
56
63
  ATTRIBUTE = /\A\s*@(?<name>.*?)\s+(?<value>.*?)\z/
57
64
 
65
+ # The attribute lines of the comment block.
66
+ # e.g. `@return [String]`.
67
+ #
68
+ # @yield [String]
69
+ # @return [Enumerable]
58
70
  def attributes
59
71
  return to_enum(:attributes) unless block_given?
60
72
 
@@ -67,6 +79,11 @@ module Bake
67
79
 
68
80
  PARAMETER = /\A\s*@param\s+(?<name>.*?)\s+\[(?<type>.*?)\]\s+(?<details>.*?)\z/
69
81
 
82
+ # The parameter lines of the comment block.
83
+ # e.g. `@param value [String] The value.`
84
+ #
85
+ # @yield [String]
86
+ # @return [Enumerable]
70
87
  def parameters
71
88
  return to_enum(:parameters) unless block_given?
72
89
 
@@ -21,7 +21,10 @@
21
21
  require_relative 'scope'
22
22
 
23
23
  module Bake
24
+ # Represents a directory which contains bakefiles.
24
25
  class Loader
26
+ # Initialize the loader with the specified root path.
27
+ # @param root [String] A file-system path.
25
28
  def initialize(root, name: nil)
26
29
  @root = root
27
30
  @name = name
@@ -31,8 +34,12 @@ module Bake
31
34
  "#{self.class} #{@name || @root}"
32
35
  end
33
36
 
37
+ # The root path for this loader.
34
38
  attr :root
35
39
 
40
+ # Enumerate all bakefiles within the loaders root directory.
41
+ # @block `{|path| ...}`
42
+ # @yield path [String] The Ruby source file path.
36
43
  def each
37
44
  return to_enum unless block_given?
38
45
 
@@ -41,18 +48,8 @@ module Bake
41
48
  end
42
49
  end
43
50
 
44
- def recipe_for(path)
45
- if book = lookup(path)
46
- return book.lookup(path.last)
47
- else
48
- *path, name = *path
49
-
50
- if book = lookup(path)
51
- return book.lookup(name)
52
- end
53
- end
54
- end
55
-
51
+ # Load the {Scope} for the specified relative path within this loader, if it exists.
52
+ # @param path [Array(String)] A relative path.
56
53
  def scope_for(path)
57
54
  *directory, file = *path
58
55
 
@@ -23,9 +23,12 @@ require 'console'
23
23
  require_relative 'loader'
24
24
 
25
25
  module Bake
26
+ # Structured access to the working directory and loaded gems for loading bakefiles.
26
27
  class Loaders
27
28
  include Enumerable
28
29
 
30
+ # Create a loader using the specified working directory.
31
+ # @param working_directory [String]
29
32
  def self.default(working_directory)
30
33
  loaders = self.new
31
34
 
@@ -34,15 +37,20 @@ module Bake
34
37
  return loaders
35
38
  end
36
39
 
40
+ # Initialize an empty array of loaders.
37
41
  def initialize
38
42
  @roots = {}
39
43
  @ordered = Array.new
40
44
  end
41
45
 
46
+ # Whether any loaders are defined.
47
+ # @return [Boolean]
42
48
  def empty?
43
49
  @ordered.empty?
44
50
  end
45
51
 
52
+ # Add loaders according to the current working directory and loaded gems.
53
+ # @param working_directory [String]
46
54
  def append_defaults(working_directory)
47
55
  # Load recipes from working directory:
48
56
  self.append_path(working_directory)
@@ -51,32 +59,26 @@ module Bake
51
59
  self.append_from_gems
52
60
  end
53
61
 
62
+ # Enumerate the loaders in order.
54
63
  def each(&block)
55
- return to_enum unless block_given?
56
-
57
64
  @ordered.each(&block)
58
65
  end
59
66
 
67
+ # Append a specific project path to the search path for recipes.
68
+ # The computed path will have `bake` appended to it.
69
+ # @param current [String] The path to add.
60
70
  def append_path(current = Dir.pwd, **options)
61
- recipes_path = File.join(current, "recipes")
62
71
  bake_path = File.join(current, "bake")
63
72
 
64
73
  if File.directory?(bake_path)
65
74
  return insert(bake_path, **options)
66
75
  end
67
76
 
68
- if File.directory?(recipes_path)
69
- Console.logger.warn(self) do |buffer|
70
- buffer.puts "Recipes path: #{recipes_path.inspect} is deprecated."
71
- buffer.puts "Please use #{bake_path.inspect} instead."
72
- end
73
-
74
- return insert(recipes_path, **options)
75
- end
76
-
77
77
  return false
78
78
  end
79
79
 
80
+ # Search from the current working directory until a suitable bakefile is found and add it.
81
+ # @param current [String] The path to start searching from.
80
82
  def append_from_root(current = Dir.pwd, **options)
81
83
  while current
82
84
  append_path(current, **options)
@@ -91,6 +93,7 @@ module Bake
91
93
  end
92
94
  end
93
95
 
96
+ # Enumerate all loaded gems and add them.
94
97
  def append_from_gems
95
98
  Gem.loaded_specs.each do |name, spec|
96
99
  Console.logger.debug(self) {"Checking gem #{name}: #{spec.full_gem_path}..."}
@@ -101,12 +104,6 @@ module Bake
101
104
  end
102
105
  end
103
106
 
104
- def append_from_paths(paths, **options)
105
- paths.each do |path|
106
- append_path(path, **options)
107
- end
108
- end
109
-
110
107
  protected
111
108
 
112
109
  def insert(directory, **options)
@@ -22,7 +22,13 @@ require_relative 'types'
22
22
  require_relative 'documentation'
23
23
 
24
24
  module Bake
25
+ # Structured access to an instance method in a bakefile.
25
26
  class Recipe
27
+ # Initialize the recipe.
28
+ #
29
+ # @param instance [Base] The instance this recipe is attached to.
30
+ # @param name [String] The method name.
31
+ # @param method [Method | Nil] The method if already known.
26
32
  def initialize(instance, name, method = nil)
27
33
  @instance = instance
28
34
  @name = name
@@ -35,21 +41,29 @@ module Bake
35
41
  @arity = nil
36
42
  end
37
43
 
44
+ # The {Base} instance that this recipe is attached to.
38
45
  attr :instance
46
+
47
+ # The name of this recipe.
39
48
  attr :name
40
49
 
50
+ # Sort by location in source file.
41
51
  def <=> other
42
52
  self.source_location <=> other.source_location
43
53
  end
44
54
 
55
+ # The method implementation.
45
56
  def method
46
57
  @method ||= @instance.method(@name)
47
58
  end
48
59
 
60
+ # The source location of this recipe.
49
61
  def source_location
50
62
  self.method.source_location
51
63
  end
52
64
 
65
+ # The recipe's formal parameters, if any.
66
+ # @return [Array | Nil]
53
67
  def parameters
54
68
  parameters = method.parameters
55
69
 
@@ -58,6 +72,8 @@ module Bake
58
72
  end
59
73
  end
60
74
 
75
+ # Whether this recipe has optional arguments.
76
+ # @return [Boolean]
61
77
  def options?
62
78
  if parameters = self.parameters
63
79
  type, name = parameters.last
@@ -66,6 +82,7 @@ module Bake
66
82
  end
67
83
  end
68
84
 
85
+ # The command name for this recipe.
69
86
  def command
70
87
  @command ||= compute_command
71
88
  end
@@ -74,6 +91,7 @@ module Bake
74
91
  self.command
75
92
  end
76
93
 
94
+ # The method's arity, the required number of positional arguments.
77
95
  def arity
78
96
  if @arity.nil?
79
97
  @arity = method.parameters.count{|type, name| type == :req}
@@ -82,6 +100,10 @@ module Bake
82
100
  return @arity
83
101
  end
84
102
 
103
+ # Process command line arguments into the ordered and optional arguments.
104
+ # @param arguments [Array(String)] The command line arguments
105
+ # @return ordered [Array]
106
+ # @return options [Hash]
85
107
  def prepare(arguments)
86
108
  offset = 0
87
109
  ordered = []
@@ -119,6 +141,7 @@ module Bake
119
141
  return ordered, options
120
142
  end
121
143
 
144
+ # Call the recipe with the specified arguments and options.
122
145
  def call(*arguments, **options)
123
146
  if options?
124
147
  @instance.send(@name, *arguments, **options)
@@ -128,22 +151,20 @@ module Bake
128
151
  end
129
152
  end
130
153
 
131
- def explain(context, *arguments, **options)
132
- if options?
133
- puts "#{self}(#{arguments.join(", ")}, #{options.inspect})"
134
- else
135
- puts "#{self}(#{arguments.join(", ")})"
136
- end
137
- end
138
-
154
+ # Any comments associated with the source code which defined the method.
155
+ # @return [Array(String)] The comment lines.
139
156
  def comments
140
157
  @comments ||= read_comments
141
158
  end
142
159
 
160
+ # The documentation object which provides structured access to the {comments}.
161
+ # @return [Documentation]
143
162
  def documentation
144
163
  @documentation ||= Documentation.new(self.comments)
145
164
  end
146
165
 
166
+ # The documented type signature of the recipe.
167
+ # @return [Array] An array of {Types} instances.
147
168
  def types
148
169
  @types ||= read_types
149
170
  end
@@ -21,7 +21,9 @@
21
21
  require_relative 'recipe'
22
22
 
23
23
  module Bake
24
+ # Used for containing all methods defined in a bakefile.
24
25
  module Scope
26
+ # Load the specified file into a unique scope module, which can then be included into a {Base} instance.
25
27
  def self.load(file_path, path = [])
26
28
  scope = Module.new
27
29
  scope.extend(self)
@@ -38,10 +40,11 @@ module Bake
38
40
  "Bake::Scope<#{self.const_get(:FILE_PATH)}>"
39
41
  end
40
42
 
41
- def recipe(name, **options, &block)
42
- define_method(name, &block)
43
- end
44
-
43
+ # Recipes defined in this scope.
44
+ #
45
+ # @block `{|recipe| ...}`
46
+ # @yield recipe [Recipe]
47
+ # @return [Enumerable]
45
48
  def recipes
46
49
  return to_enum(:recipes) unless block_given?
47
50
 
@@ -52,10 +55,14 @@ module Bake
52
55
  end
53
56
  end
54
57
 
58
+ # The path of the file that was used to {load} this scope.
55
59
  def path
56
60
  self.const_get(:PATH)
57
61
  end
58
62
 
63
+ # Look up a recipe with a specific name.
64
+ #
65
+ # @param name [String] The instance method to look up.
59
66
  def recipe_for(name)
60
67
  Recipe.new(self, name, self.instance_method(name))
61
68
  end
@@ -20,43 +20,70 @@
20
20
 
21
21
  module Bake
22
22
  module Types
23
- module Type
24
- def | other
25
- Any.new([self, other])
26
- end
27
- end
28
-
23
+ # An ordered list of types. The first type to match the input is used.
24
+ #
25
+ # ```ruby
26
+ # type = Bake::Types::Any(Bake::Types::String, Bake::Types::Integer)
27
+ # ```
28
+ #
29
29
  class Any
30
+ # Initialize the instance with an array of types.
31
+ # @param types [Array] the array of types.
30
32
  def initialize(types)
31
33
  @types = types
32
34
  end
33
35
 
36
+ # Create a copy of the current instance with the other type appended.
37
+ # @param other [Type] the type instance to append.
34
38
  def | other
35
39
  self.class.new([*@types, other])
36
40
  end
37
41
 
42
+ # Whether any of the listed types is a composite type.
43
+ # @return [Boolean] true if any of the listed types is `composite?`.
38
44
  def composite?
39
45
  @types.any?{|type| type.composite?}
40
46
  end
41
47
 
48
+ # Parse an input string, trying the listed types in order, returning the first one which doesn't raise an exception.
49
+ # @param input [String] the input to parse, e.g. `"5"`.
42
50
  def parse(input)
43
51
  @types.each do |type|
44
52
  return type.parse(input)
45
53
  rescue
46
- # Ignore
54
+ # Ignore.
47
55
  end
48
56
  end
49
57
 
58
+ # As a class type, accepts any value.
50
59
  def self.parse(value)
51
60
  value
52
61
  end
53
62
 
63
+ # Generate a readable string representation of the listed types.
54
64
  def to_s
55
65
  "any of #{@types.join(', ')}"
56
66
  end
57
67
  end
58
68
 
59
- def self.Any(types)
69
+ # An extension module which allows constructing `Any` types using the `|` operator.
70
+ module Type
71
+ # Create an instance of `Any` with the arguments as types.
72
+ # @param other [Type] the alternative type to match.
73
+ def | other
74
+ Any.new([self, other])
75
+ end
76
+ end
77
+
78
+ # A type constructor.
79
+ #
80
+ # ```ruby
81
+ # Any(Integer, String)
82
+ # ```
83
+ #
84
+ # See [Any.initialize](#Bake::Types::Any::initialize).
85
+ #
86
+ def self.Any(*types)
60
87
  Any.new(types)
61
88
  end
62
89
  end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Bake
22
- VERSION = "0.12.1"
22
+ VERSION = "0.13.0"
23
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-30 00:00:00.000000000 Z
11
+ date: 2020-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: samovar
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: utopia-project
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: covered
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -109,8 +123,10 @@ files:
109
123
  - bake.gemspec
110
124
  - bake.rb
111
125
  - bin/bake
112
- - example.png
113
126
  - gems.rb
127
+ - guides/command-line-interface/README.md
128
+ - guides/gem-integration/README.md
129
+ - guides/project-integration/README.md
114
130
  - lib/bake.rb
115
131
  - lib/bake/base.rb
116
132
  - lib/bake/command.rb
Binary file