bake 0.10.0 → 0.14.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.
@@ -19,37 +19,51 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require_relative 'types'
22
+ require_relative 'documentation'
22
23
 
23
24
  module Bake
24
- PARAMETER = /@param\s+(?<name>.*?)\s+\[(?<type>.*?)\]\s+(?<details>.*?)\Z/
25
-
25
+ # Structured access to an instance method in a bakefile.
26
26
  class Recipe
27
+ # Initialize the recipe.
28
+ #
29
+ # @parameter instance [Base] The instance this recipe is attached to.
30
+ # @parameter name [String] The method name.
31
+ # @parameter method [Method | Nil] The method if already known.
27
32
  def initialize(instance, name, method = nil)
28
33
  @instance = instance
29
34
  @name = name
30
35
  @command = nil
31
- @description = nil
36
+ @comments = nil
32
37
  @types = nil
38
+ @documentation = nil
33
39
 
34
40
  @method = method
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
+ # @returns [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
+ # @returns [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
+ # @parameter arguments [Array(String)] The command line arguments
105
+ # @returns ordered [Array]
106
+ # @returns 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,18 +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
154
+ # Any comments associated with the source code which defined the method.
155
+ # @returns [Array(String)] The comment lines.
156
+ def comments
157
+ @comments ||= read_comments
137
158
  end
138
159
 
139
- def description
140
- @description ||= read_description
160
+ # The documentation object which provides structured access to the {comments}.
161
+ # @returns [Documentation]
162
+ def documentation
163
+ @documentation ||= Documentation.new(self.comments)
141
164
  end
142
165
 
166
+ # The documented type signature of the recipe.
167
+ # @returns [Array] An array of {Types} instances.
143
168
  def types
144
169
  @types ||= read_types
145
170
  end
@@ -158,23 +183,21 @@ module Bake
158
183
  end
159
184
  end
160
185
 
161
- def read_description
186
+ COMMENT = /\A\s*\#\s?(.*?)\Z/
187
+
188
+ def read_comments
162
189
  file, line_number = self.method.source_location
163
190
 
164
191
  lines = File.readlines(file)
165
192
  line_index = line_number - 1
166
193
 
167
- # Legacy "recipe" syntax:
168
- if match = lines[line_index].match(/description: "(.*?)"/)
169
- return [match[1]]
170
- end
171
-
172
194
  description = []
173
195
  line_index -= 1
174
196
 
175
197
  # Extract comment preceeding method:
176
198
  while line = lines[line_index]
177
- if match = line.match(/^\s*\#\s?(.*?)$/)
199
+ # \Z matches a trailing newline:
200
+ if match = line.match(COMMENT)
178
201
  description.unshift(match[1])
179
202
  else
180
203
  break
@@ -189,10 +212,8 @@ module Bake
189
212
  def read_types
190
213
  types = {}
191
214
 
192
- description.each do |description|
193
- if fields = PARAMETER.match(description)
194
- types[fields[:name].to_sym] = Types.parse(fields[:type])
195
- end
215
+ self.documentation.parameters do |parameter|
216
+ types[parameter[:name].to_sym] = Types.parse(parameter[:type])
196
217
  end
197
218
 
198
219
  return types
@@ -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
+ # @yields {|recipe| ...}
46
+ # @parameter recipe [Recipe]
47
+ # @returns [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
+ # @parameter 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
@@ -24,8 +24,10 @@ require_relative 'types/boolean'
24
24
  require_relative 'types/decimal'
25
25
  require_relative 'types/float'
26
26
  require_relative 'types/hash'
27
+ require_relative 'types/input'
27
28
  require_relative 'types/integer'
28
29
  require_relative 'types/nil'
30
+ require_relative 'types/output'
29
31
  require_relative 'types/string'
30
32
  require_relative 'types/symbol'
31
33
  require_relative 'types/tuple'
@@ -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
+ # @parameter 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
+ # @parameter 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
+ # @returns [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
+ # @parameter 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
+ # @parameter 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
@@ -0,0 +1,42 @@
1
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'any'
22
+
23
+ module Bake
24
+ module Types
25
+ module Input
26
+ extend Type
27
+
28
+ def self.composite?
29
+ false
30
+ end
31
+
32
+ def self.parse(input)
33
+ case input
34
+ when '-'
35
+ return $stdin
36
+ else
37
+ File.open(input)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'any'
22
+
23
+ module Bake
24
+ module Types
25
+ module Output
26
+ extend Type
27
+
28
+ def self.composite?
29
+ false
30
+ end
31
+
32
+ def self.parse(input)
33
+ case input
34
+ when '-'
35
+ return $stdout
36
+ else
37
+ File.open(input, "w")
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Bake
22
- VERSION = "0.10.0"
22
+ VERSION = "0.14.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.10.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-23 00:00:00.000000000 Z
11
+ date: 2020-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: samovar
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.1'
27
- - !ruby/object:Gem::Dependency
28
- name: bake-bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: covered
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,21 +66,7 @@ dependencies:
80
66
  - - ">="
81
67
  - !ruby/object:Gem::Version
82
68
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- description:
69
+ description:
98
70
  email:
99
71
  - samuel.williams@oriontransfer.co.nz
100
72
  executables:
@@ -109,8 +81,12 @@ files:
109
81
  - bake.gemspec
110
82
  - bake.rb
111
83
  - bin/bake
112
- - example.png
113
84
  - gems.rb
85
+ - guides/command-line-interface/README.md
86
+ - guides/gem-integration/README.md
87
+ - guides/getting-started/README.md
88
+ - guides/links.yaml
89
+ - guides/project-integration/README.md
114
90
  - lib/bake.rb
115
91
  - lib/bake/base.rb
116
92
  - lib/bake/command.rb
@@ -118,6 +94,7 @@ files:
118
94
  - lib/bake/command/list.rb
119
95
  - lib/bake/command/top.rb
120
96
  - lib/bake/context.rb
97
+ - lib/bake/documentation.rb
121
98
  - lib/bake/loader.rb
122
99
  - lib/bake/loaders.rb
123
100
  - lib/bake/recipe.rb
@@ -129,8 +106,10 @@ files:
129
106
  - lib/bake/types/decimal.rb
130
107
  - lib/bake/types/float.rb
131
108
  - lib/bake/types/hash.rb
109
+ - lib/bake/types/input.rb
132
110
  - lib/bake/types/integer.rb
133
111
  - lib/bake/types/nil.rb
112
+ - lib/bake/types/output.rb
134
113
  - lib/bake/types/string.rb
135
114
  - lib/bake/types/symbol.rb
136
115
  - lib/bake/types/tuple.rb
@@ -140,7 +119,7 @@ licenses:
140
119
  - MIT
141
120
  metadata:
142
121
  donation_uri: https://github.com/sponsors/ioquatix
143
- post_install_message:
122
+ post_install_message:
144
123
  rdoc_options: []
145
124
  require_paths:
146
125
  - lib
@@ -156,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
135
  version: '0'
157
136
  requirements: []
158
137
  rubygems_version: 3.1.2
159
- signing_key:
138
+ signing_key:
160
139
  specification_version: 4
161
140
  summary: A replacement for rake with a simpler syntax.
162
141
  test_files: []