klenod-build 0.0.1

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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +29 -0
  3. data/lib/klenod/build/asset.rb +235 -0
  4. data/lib/klenod/build/asset_compression.rb +58 -0
  5. data/lib/klenod/build/asset_generation_queue.rb +50 -0
  6. data/lib/klenod/build/cli/application.rb +108 -0
  7. data/lib/klenod/build/cli.rb +3 -0
  8. data/lib/klenod/build/config.rb +142 -0
  9. data/lib/klenod/build/context.rb +370 -0
  10. data/lib/klenod/build/dependency.rb +21 -0
  11. data/lib/klenod/build/errors.rb +175 -0
  12. data/lib/klenod/build/filesystem_resolver.rb +147 -0
  13. data/lib/klenod/build/graph/invalidator.rb +246 -0
  14. data/lib/klenod/build/graph.rb +864 -0
  15. data/lib/klenod/build/graphviz.rb +282 -0
  16. data/lib/klenod/build/hashing.rb +21 -0
  17. data/lib/klenod/build/invalidation_result.rb +55 -0
  18. data/lib/klenod/build/load_result.rb +7 -0
  19. data/lib/klenod/build/loaded_module.rb +38 -0
  20. data/lib/klenod/build/module_id.rb +100 -0
  21. data/lib/klenod/build/module_record.rb +22 -0
  22. data/lib/klenod/build/plugin.rb +35 -0
  23. data/lib/klenod/build/plugins/class_names_runtime.rb +125 -0
  24. data/lib/klenod/build/plugins/component_defaults.rb +12 -0
  25. data/lib/klenod/build/plugins/data_plugin.rb +117 -0
  26. data/lib/klenod/build/plugins/gem_import_plugin.rb +125 -0
  27. data/lib/klenod/build/plugins/google_fonts_plugin/font_metrics.json +17687 -0
  28. data/lib/klenod/build/plugins/google_fonts_plugin/font_metrics.rb +105 -0
  29. data/lib/klenod/build/plugins/google_fonts_plugin/font_metrics.txt +31 -0
  30. data/lib/klenod/build/plugins/google_fonts_plugin.rb +387 -0
  31. data/lib/klenod/build/plugins/haml_plugin/companions.rb +40 -0
  32. data/lib/klenod/build/plugins/haml_plugin/errors.rb +114 -0
  33. data/lib/klenod/build/plugins/haml_plugin/helper_source.rb +123 -0
  34. data/lib/klenod/build/plugins/haml_plugin/parser.rb +85 -0
  35. data/lib/klenod/build/plugins/haml_plugin/transformer/ruby_builder.rb +1039 -0
  36. data/lib/klenod/build/plugins/haml_plugin/transformer.rb +766 -0
  37. data/lib/klenod/build/plugins/haml_plugin.rb +369 -0
  38. data/lib/klenod/build/plugins/image_plugin.rb +401 -0
  39. data/lib/klenod/build/plugins/intl_plugin.rb +34 -0
  40. data/lib/klenod/build/plugins/markdown_compiler.rb +180 -0
  41. data/lib/klenod/build/plugins/markdown_plugin.rb +161 -0
  42. data/lib/klenod/build/plugins/router_plugin.rb +942 -0
  43. data/lib/klenod/build/plugins/ruby_plugin.rb +34 -0
  44. data/lib/klenod/build/plugins/svg_plugin.rb +197 -0
  45. data/lib/klenod/build/plugins.rb +22 -0
  46. data/lib/klenod/build/profiler.rb +79 -0
  47. data/lib/klenod/build/resolution_error_formatter.rb +42 -0
  48. data/lib/klenod/build/resolver.rb +95 -0
  49. data/lib/klenod/build/ruby_import_rewriter.rb +436 -0
  50. data/lib/klenod/build/source_map/editor.rb +110 -0
  51. data/lib/klenod/build/source_map/map.rb +168 -0
  52. data/lib/klenod/build/source_map/vlq.rb +68 -0
  53. data/lib/klenod/build/source_map.rb +12 -0
  54. data/lib/klenod/build/transform_result.rb +12 -0
  55. data/lib/klenod/build/version.rb +7 -0
  56. data/lib/klenod/build/watched_pattern.rb +11 -0
  57. data/lib/klenod/build/watcher.rb +141 -0
  58. data/lib/klenod/build.rb +15 -0
  59. metadata +310 -0
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Klenod
4
+ module Build
5
+ module SourceMap
6
+ module VLQ
7
+ BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
8
+ BASE64_VALUES = BASE64_CHARS.each_char.with_index.to_h.freeze
9
+ CONTINUATION_BIT = 32
10
+ VALUE_MASK = 31
11
+
12
+ module_function
13
+
14
+ def decode(segment)
15
+ values = []
16
+ value = 0
17
+ shift = 0
18
+
19
+ segment.each_char do |char|
20
+ digit = BASE64_VALUES.fetch(char)
21
+ continuation = (digit & CONTINUATION_BIT) != 0
22
+ digit &= VALUE_MASK
23
+ value += digit << shift
24
+
25
+ if continuation
26
+ shift += 5
27
+ else
28
+ values << from_vlq_signed(value)
29
+ value = 0
30
+ shift = 0
31
+ end
32
+ end
33
+
34
+ values
35
+ end
36
+
37
+ def encode(values)
38
+ values.map { encode_value(it) }.join
39
+ end
40
+
41
+ def encode_value(value)
42
+ vlq = to_vlq_signed(value)
43
+ encoded = +""
44
+
45
+ loop do
46
+ digit = vlq & VALUE_MASK
47
+ vlq >>= 5
48
+ digit |= CONTINUATION_BIT if vlq > 0
49
+ encoded << BASE64_CHARS[digit]
50
+ break if vlq == 0
51
+ end
52
+
53
+ encoded
54
+ end
55
+
56
+ def to_vlq_signed(value)
57
+ (value < 0) ? ((-value) << 1) + 1 : value << 1
58
+ end
59
+
60
+ def from_vlq_signed(value)
61
+ negative = (value & 1) == 1
62
+ shifted = value >> 1
63
+ negative ? -shifted : shifted
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "source_map/editor"
4
+ require_relative "source_map/map"
5
+ require_relative "source_map/vlq"
6
+
7
+ module Klenod
8
+ module Build
9
+ module SourceMap
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Klenod
4
+ module Build
5
+ TransformResult =
6
+ Data.define(:code, :dependencies, :source_map, :assets, :watched_patterns, :metadata) do
7
+ def self.identity(code)
8
+ new(code, [], nil, [], [], {})
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Klenod
4
+ module Build
5
+ VERSION = "0.0.1"
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Klenod
4
+ module Build
5
+ WatchedPattern = Data.define(:importer_id, :glob, :kind, :metadata) do
6
+ def match?(path)
7
+ File.fnmatch?(glob, path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "listen"
4
+
5
+ module Klenod
6
+ module Build
7
+ UpdateEvent = Data.define(:changed_paths, :removed_paths, :graph_version, :result) do
8
+ def asset_changes
9
+ result.asset_changes
10
+ end
11
+
12
+ def asset_updates
13
+ result.asset_updates
14
+ end
15
+ end
16
+
17
+ class Watcher
18
+ class PendingChanges
19
+ def initialize
20
+ @changed_paths = Set.new
21
+ @removed_paths = Set.new
22
+ end
23
+
24
+ def add(changed_paths, removed_paths)
25
+ changed_paths.each do |path|
26
+ @changed_paths << path
27
+ @removed_paths.delete(path)
28
+ end
29
+
30
+ removed_paths.each do |path|
31
+ @removed_paths << path
32
+ @changed_paths.delete(path)
33
+ end
34
+ end
35
+
36
+ def empty?
37
+ @changed_paths.empty? && @removed_paths.empty?
38
+ end
39
+
40
+ def normalized
41
+ changed_paths = Set.new
42
+ removed_paths = Set.new
43
+
44
+ (@changed_paths + @removed_paths).each do |path|
45
+ if File.exist?(path)
46
+ changed_paths << path
47
+ else
48
+ removed_paths << path
49
+ end
50
+ end
51
+
52
+ [changed_paths.to_a.freeze, removed_paths.to_a.freeze]
53
+ end
54
+ end
55
+
56
+ def initialize(source_dir:, context:, debounce_interval: 0.1)
57
+ @source_dir = source_dir
58
+ @context = context
59
+ @debounce_interval = debounce_interval
60
+ @graph_version = 0
61
+ @pending_changes = PendingChanges.new
62
+ @pending_mutex = Mutex.new
63
+ @pending_condition = ConditionVariable.new
64
+ @last_change_at = nil
65
+ @stopping = false
66
+ end
67
+
68
+ def start
69
+ @worker_thread = Thread.new { process_pending_updates }
70
+ @listener =
71
+ Listen.to(@source_dir) do |modified, added, removed|
72
+ enqueue_update(modified + added, removed)
73
+ end
74
+ @listener.start
75
+ end
76
+
77
+ def stop
78
+ @listener&.stop
79
+ @pending_mutex.synchronize do
80
+ @stopping = true
81
+ @pending_condition.broadcast
82
+ end
83
+ @worker_thread&.join
84
+ end
85
+
86
+ private
87
+
88
+ def enqueue_update(changed_paths, removed_paths)
89
+ @pending_mutex.synchronize do
90
+ @pending_changes.add(changed_paths, removed_paths)
91
+ @last_change_at = monotonic_time
92
+ @pending_condition.signal
93
+ end
94
+ end
95
+
96
+ def process_pending_updates
97
+ loop do
98
+ changed_paths, removed_paths = wait_for_pending_update
99
+ break unless changed_paths
100
+
101
+ emit_update(changed_paths, removed_paths)
102
+ end
103
+ end
104
+
105
+ def wait_for_pending_update
106
+ @pending_mutex.synchronize do
107
+ @pending_condition.wait(@pending_mutex) while !@stopping && @pending_changes.empty?
108
+ return nil if @stopping
109
+
110
+ wait_for_debounce_window
111
+ return nil if @stopping
112
+
113
+ changes = @pending_changes
114
+ @pending_changes = PendingChanges.new
115
+ changes.normalized
116
+ end
117
+ end
118
+
119
+ def wait_for_debounce_window
120
+ loop do
121
+ remaining = @debounce_interval - (monotonic_time - @last_change_at)
122
+ break if remaining <= 0
123
+
124
+ @pending_condition.wait(@pending_mutex, remaining)
125
+ break if @stopping
126
+ end
127
+ end
128
+
129
+ def emit_update(changed_paths, removed_paths)
130
+ @graph_version += 1
131
+ result = @context.invalidate_paths(changed_paths, removed_paths: removed_paths)
132
+
133
+ @context.emit_update(UpdateEvent.new(changed_paths, removed_paths, @graph_version, result))
134
+ end
135
+
136
+ def monotonic_time
137
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "build/version"
4
+ require "klenod/runtime"
5
+ require_relative "build/context"
6
+
7
+ module Klenod
8
+ class Error < StandardError; end unless const_defined?(:Error, false)
9
+
10
+ module Build
11
+ autoload :Graphviz, "klenod/build/graphviz"
12
+ autoload :UpdateEvent, "klenod/build/watcher"
13
+ autoload :Watcher, "klenod/build/watcher"
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,310 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: klenod-build
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrés Alin
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: klenod-runtime
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '='
17
+ - !ruby/object:Gem::Version
18
+ version: 0.0.1
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - '='
24
+ - !ruby/object:Gem::Version
25
+ version: 0.0.1
26
+ - !ruby/object:Gem::Dependency
27
+ name: async
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.42'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.42'
40
+ - !ruby/object:Gem::Dependency
41
+ name: async-http
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.95.1
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.95.1
54
+ - !ruby/object:Gem::Dependency
55
+ name: brotli
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.8'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.8'
68
+ - !ruby/object:Gem::Dependency
69
+ name: image_size
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.6'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.6'
82
+ - !ruby/object:Gem::Dependency
83
+ name: kramdown
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.5'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.5'
96
+ - !ruby/object:Gem::Dependency
97
+ name: kramdown-parser-gfm
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.1'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.1'
110
+ - !ruby/object:Gem::Dependency
111
+ name: listen
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '3.10'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.10'
124
+ - !ruby/object:Gem::Dependency
125
+ name: protocol-url
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '0.4'
131
+ type: :runtime
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '0.4'
138
+ - !ruby/object:Gem::Dependency
139
+ name: rmagick
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '7.0'
145
+ type: :runtime
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '7.0'
152
+ - !ruby/object:Gem::Dependency
153
+ name: samovar
154
+ requirement: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '2.5'
159
+ type: :runtime
160
+ prerelease: false
161
+ version_requirements: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '2.5'
166
+ - !ruby/object:Gem::Dependency
167
+ name: syntax_tree
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '6.3'
173
+ type: :runtime
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '6.3'
180
+ - !ruby/object:Gem::Dependency
181
+ name: syntax_tree-haml
182
+ requirement: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - "~>"
185
+ - !ruby/object:Gem::Version
186
+ version: '4.0'
187
+ type: :runtime
188
+ prerelease: false
189
+ version_requirements: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '4.0'
194
+ - !ruby/object:Gem::Dependency
195
+ name: toml-rb
196
+ requirement: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: '4.2'
201
+ type: :runtime
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '4.2'
208
+ - !ruby/object:Gem::Dependency
209
+ name: tsort
210
+ requirement: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: 0.2.0
215
+ type: :runtime
216
+ prerelease: false
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "~>"
220
+ - !ruby/object:Gem::Version
221
+ version: 0.2.0
222
+ description: Klenod build constructs Ruby module graphs, runs plugins, emits assets,
223
+ and serializes runtime bundles.
224
+ email:
225
+ - andreas.alin@gmail.com
226
+ executables: []
227
+ extensions: []
228
+ extra_rdoc_files: []
229
+ files:
230
+ - README.md
231
+ - lib/klenod/build.rb
232
+ - lib/klenod/build/asset.rb
233
+ - lib/klenod/build/asset_compression.rb
234
+ - lib/klenod/build/asset_generation_queue.rb
235
+ - lib/klenod/build/cli.rb
236
+ - lib/klenod/build/cli/application.rb
237
+ - lib/klenod/build/config.rb
238
+ - lib/klenod/build/context.rb
239
+ - lib/klenod/build/dependency.rb
240
+ - lib/klenod/build/errors.rb
241
+ - lib/klenod/build/filesystem_resolver.rb
242
+ - lib/klenod/build/graph.rb
243
+ - lib/klenod/build/graph/invalidator.rb
244
+ - lib/klenod/build/graphviz.rb
245
+ - lib/klenod/build/hashing.rb
246
+ - lib/klenod/build/invalidation_result.rb
247
+ - lib/klenod/build/load_result.rb
248
+ - lib/klenod/build/loaded_module.rb
249
+ - lib/klenod/build/module_id.rb
250
+ - lib/klenod/build/module_record.rb
251
+ - lib/klenod/build/plugin.rb
252
+ - lib/klenod/build/plugins.rb
253
+ - lib/klenod/build/plugins/class_names_runtime.rb
254
+ - lib/klenod/build/plugins/component_defaults.rb
255
+ - lib/klenod/build/plugins/data_plugin.rb
256
+ - lib/klenod/build/plugins/gem_import_plugin.rb
257
+ - lib/klenod/build/plugins/google_fonts_plugin.rb
258
+ - lib/klenod/build/plugins/google_fonts_plugin/font_metrics.json
259
+ - lib/klenod/build/plugins/google_fonts_plugin/font_metrics.rb
260
+ - lib/klenod/build/plugins/google_fonts_plugin/font_metrics.txt
261
+ - lib/klenod/build/plugins/haml_plugin.rb
262
+ - lib/klenod/build/plugins/haml_plugin/companions.rb
263
+ - lib/klenod/build/plugins/haml_plugin/errors.rb
264
+ - lib/klenod/build/plugins/haml_plugin/helper_source.rb
265
+ - lib/klenod/build/plugins/haml_plugin/parser.rb
266
+ - lib/klenod/build/plugins/haml_plugin/transformer.rb
267
+ - lib/klenod/build/plugins/haml_plugin/transformer/ruby_builder.rb
268
+ - lib/klenod/build/plugins/image_plugin.rb
269
+ - lib/klenod/build/plugins/intl_plugin.rb
270
+ - lib/klenod/build/plugins/markdown_compiler.rb
271
+ - lib/klenod/build/plugins/markdown_plugin.rb
272
+ - lib/klenod/build/plugins/router_plugin.rb
273
+ - lib/klenod/build/plugins/ruby_plugin.rb
274
+ - lib/klenod/build/plugins/svg_plugin.rb
275
+ - lib/klenod/build/profiler.rb
276
+ - lib/klenod/build/resolution_error_formatter.rb
277
+ - lib/klenod/build/resolver.rb
278
+ - lib/klenod/build/ruby_import_rewriter.rb
279
+ - lib/klenod/build/source_map.rb
280
+ - lib/klenod/build/source_map/editor.rb
281
+ - lib/klenod/build/source_map/map.rb
282
+ - lib/klenod/build/source_map/vlq.rb
283
+ - lib/klenod/build/transform_result.rb
284
+ - lib/klenod/build/version.rb
285
+ - lib/klenod/build/watched_pattern.rb
286
+ - lib/klenod/build/watcher.rb
287
+ homepage: https://github.com/aalin/klenod
288
+ licenses:
289
+ - MIT
290
+ metadata:
291
+ homepage_uri: https://github.com/aalin/klenod
292
+ source_code_uri: https://github.com/aalin/klenod/tree/main/gems/klenod-build
293
+ rdoc_options: []
294
+ require_paths:
295
+ - lib
296
+ required_ruby_version: !ruby/object:Gem::Requirement
297
+ requirements:
298
+ - - ">="
299
+ - !ruby/object:Gem::Version
300
+ version: 4.0.6
301
+ required_rubygems_version: !ruby/object:Gem::Requirement
302
+ requirements:
303
+ - - ">="
304
+ - !ruby/object:Gem::Version
305
+ version: '0'
306
+ requirements: []
307
+ rubygems_version: 4.0.16
308
+ specification_version: 4
309
+ summary: Build graph and plugins for Klenod.
310
+ test_files: []