bake 0.11.0 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -32,6 +32,10 @@ module Bake
32
32
  def self.parse(input)
33
33
  if input =~ /t(rue)?|y(es)?/i
34
34
  return true
35
+ elsif input =~ /f(alse)?|n(o)?/i
36
+ return false
37
+ else
38
+ raise ArgumentError, "Cannot coerce #{input.inspect} into boolean!"
35
39
  end
36
40
  end
37
41
  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
@@ -33,7 +33,7 @@ module Bake
33
33
  if input =~ /nil|null/i
34
34
  return nil
35
35
  else
36
- raise ArgumentError, "Cannot coerce #{input} into nil!"
36
+ raise ArgumentError, "Cannot coerce #{input.inspect} into nil!"
37
37
  end
38
38
  end
39
39
  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.11.0"
22
+ VERSION = "0.14.1"
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.11.0
4
+ version: 0.14.1
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-29 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: []