yarrow 0.9.1 → 0.9.3

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: f8f774a7c3013a183129ba27e6929cb1d9cb65f784121f61d3df2c1ffba8a4fb
4
- data.tar.gz: 7f94b3a971a5fb00d089b6bbad8c12cb724d35f3e00497091130c4731534b275
3
+ metadata.gz: 2a2ebdee5113cc218a9744d5da88b01cb0e7604b4ecfe0d133f776d48d2b4b97
4
+ data.tar.gz: 967ba36fec57253eea8069f903828b8529f43802578c8be009413e4a5373e1f1
5
5
  SHA512:
6
- metadata.gz: de66835c7de07c4c84802a8adf75e57d637c4865f7a7e2f1f42f06ac0a22adbadfd067c812a6ba8a5be7e8fa03f116173f1a47777c550d38004e0683c6395685
7
- data.tar.gz: a7aff55ba63ed7cc2b493b28dd27f415c985bd55730de71732411c2d3500ee0beb0dd21a599b7110599dfb80253bef6b4204a70276b4ed794cf0f2884d3149a1
6
+ metadata.gz: 982f7c783ed933419504e6722e9ffbacaf513468a16cdb07ca4ec7ffc859d5eaed1470948d8c1ca7ce5aa00f5e0fc05b9c29a38f0f0e2972aa6d2f348aec2c7b
7
+ data.tar.gz: 4debe486afb56d7f664a0dd730db05429b2d7256a5f2789f1987339b394f404ac0f59f67d9e2f25126ad946675a46b7f910a91881d447afed148cb56eb4b5317
@@ -10,10 +10,10 @@ jobs:
10
10
  fail-fast: false
11
11
  matrix:
12
12
  os: [ubuntu-latest, macos-latest]
13
- ruby: [2.7, 3.1, 3.2]
13
+ ruby: [3.1, 3.2, "3.3.0-preview1"]
14
14
  runs-on: ${{ matrix.os }}
15
15
  steps:
16
- - uses: actions/checkout@v2
16
+ - uses: actions/checkout@v4
17
17
  - name: Set up Ruby
18
18
  uses: ruby/setup-ruby@v1
19
19
  with:
data/lib/yarrow/config.rb CHANGED
@@ -53,13 +53,13 @@ module Yarrow
53
53
  # Yarrow::Schema::Types::Map.of(Symbol)
54
54
  # )
55
55
 
56
- class Content < Yarrow::Schema::Entity[:__config_content]
56
+ class Content < Yarrow::Schema::Entity
57
57
  attribute :module, :string
58
58
  #attribute :source_map, :__config_source_map
59
59
  attribute :source_map, :hash
60
60
  end
61
61
 
62
- class Output < Yarrow::Schema::Entity[:__config_output]
62
+ class Output < Yarrow::Schema::Entity
63
63
  attribute :generator, :string
64
64
  attribute :template_dir, :path
65
65
  #attribute :scripts, :array
@@ -71,8 +71,8 @@ module Yarrow
71
71
  attribute :output_dir, :path
72
72
  attribute :meta, :any
73
73
  attribute :server, :any
74
- attribute :content, :__config_content
75
- attribute :output, :__config_output
74
+ attribute :content, :yarrow_config_content
75
+ attribute :output, :yarrow_config_output
76
76
  end
77
77
  #
78
78
  # `content_dir` and `output_dir` are placeholders and should be overriden
@@ -60,7 +60,7 @@ module Yarrow
60
60
  end
61
61
 
62
62
  def parse_toml(raw)
63
- TOML::Parser.new(raw).parsed
63
+ TomlRB.parse(raw, symbolize_keys: true)
64
64
  end
65
65
 
66
66
  def parse_json(raw)
@@ -20,11 +20,16 @@ module Yarrow
20
20
  end
21
21
 
22
22
  def inherited(class_name)
23
+ class_type = Yarrow::Schema::Types::Instance.of(class_name).accept(Hash)
24
+
23
25
  if @label
24
- class_type = Yarrow::Schema::Types::Instance.of(class_name)
25
- Yarrow::Schema::Definitions.register(@label, class_type)
26
+ label = @label
26
27
  @label = nil
28
+ else
29
+ label = Yarrow::Symbols.from_const(class_name)
27
30
  end
31
+
32
+ Yarrow::Schema::Definitions.register(label, class_type)
28
33
  end
29
34
  end
30
35
 
@@ -32,14 +37,7 @@ module Yarrow
32
37
  converted = dictionary.cast(config)
33
38
 
34
39
  converted.each_pair do |key, value|
35
- # raise "#{key} not a declared attribute" unless dictionary.key?(key)
36
- #
37
- # defined_type = dictionary[key]
38
- #
39
- # unless value.is_a?(defined_type)
40
- # raise "#{key} accepts #{defined_type} but #{value.class} given"
41
- # end
42
-
40
+ # TODO: should we represent this as an attribute set rather than instance vars?
43
41
  instance_variable_set("@#{key}", value)
44
42
  end
45
43
  end
@@ -1,15 +1,20 @@
1
1
  module Yarrow
2
2
  module Schema
3
- # class Structure < Struct
4
- # def self.inherited(subclass)
5
- # unless subclass.name
6
- # puts "CLASS"
7
- # p caller_locations[3]
8
- # else
9
- # p subclass.name.downcase.to_sym
10
- # end
11
- # end
12
- # end
3
+ class ValueType < Struct
4
+ def self.register(label)
5
+ class_type = Yarrow::Schema::Types::Instance.of(self).accept(Hash)
6
+ Yarrow::Schema::Definitions.register(label, class_type)
7
+ self
8
+ end
9
+
10
+ # Automatically register when struct is defined as a class extension
11
+ # rather than anonymous struct class.
12
+ def self.inherited(subclass)
13
+ if subclass.name
14
+ self.register(subclass.name.downcase.to_sym)
15
+ end
16
+ end
17
+ end
13
18
 
14
19
  # Value object (with comparison by value equality). This just chucks back a
15
20
  # Ruby struct but wraps the constructor with method advice that handles
@@ -33,12 +38,16 @@ module Yarrow
33
38
 
34
39
  validator = Dictionary.new(fields_spec)
35
40
 
36
- struct = Struct.new(*slots_spec, keyword_init: true, &block)
41
+ struct = ValueType.new(*slots_spec, keyword_init: true, &block)
37
42
 
38
43
  struct.define_method :initialize do |*args, **kwargs|
39
44
  attr_values = if args.any?
40
45
  raise ArgumentError.new("cannot mix slots and kwargs") if kwargs.any?
41
- Hash[slots.zip(args)]
46
+ if args.first.instance_of?(Hash) and args.count == 1
47
+ args.first
48
+ else
49
+ Hash[slots.zip(args)]
50
+ end
42
51
  else
43
52
  kwargs
44
53
  end
@@ -19,6 +19,20 @@ module Yarrow
19
19
  Object.const_get(Strings::Case.pascalcase(atom.to_s).to_sym)
20
20
  end
21
21
 
22
+ # Converts a string name of class const to a symbol atom
23
+ #
24
+ # @param [Class, String, #to_s] const_obj
25
+ # @return [Symbol]
26
+ def self.from_const(const_obj)
27
+ const_lookup = if const_obj.respond_to?(:name)
28
+ const_obj.name
29
+ else
30
+ const_obj.to_s
31
+ end
32
+
33
+ Strings::Case.underscore(const_lookup).to_sym
34
+ end
35
+
22
36
  # @param [Symbol, String] atom
23
37
  # @return [Symbol]
24
38
  def self.to_singular(atom)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module Yarrow
3
3
  APP_NAME = "Yarrow"
4
- VERSION = "0.9.1"
4
+ VERSION = "0.9.3"
5
5
  end
data/lib/yarrow.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "pathname"
2
2
  require "yaml"
3
3
  require "kramdown"
4
- require "toml"
4
+ require "toml-rb"
5
5
  require "mustache"
6
6
  require "parallel"
7
7
 
data/yarrow.gemspec CHANGED
@@ -24,8 +24,9 @@ Gem::Specification.new do |spec|
24
24
  spec.add_runtime_dependency 'parallel', '~> 1.22.1'
25
25
  spec.add_runtime_dependency 'strings-inflection', '~> 0.1'
26
26
  spec.add_runtime_dependency 'strings-case', '~> 0.3'
27
- spec.add_runtime_dependency 'toml', '~> 0.3.0'
28
- # https://github.com/joeldrapper/phlex
27
+ spec.add_runtime_dependency 'toml-rb', '~> 2.2.0'
28
+ spec.add_runtime_dependency 'shale', '~> 1.0.0'
29
+ spec.add_runtime_dependency 'phlex', '~> 1.8.1'
29
30
  spec.add_runtime_dependency 'kramdown', '~> 2.4.0'
30
31
  spec.add_development_dependency 'rake', '~> 13.0'
31
32
  spec.add_development_dependency 'rspec', '~> 3.11'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yarrow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Rickerby
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-03 00:00:00.000000000 Z
11
+ date: 2023-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -165,19 +165,47 @@ dependencies:
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0.3'
167
167
  - !ruby/object:Gem::Dependency
168
- name: toml
168
+ name: toml-rb
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: 0.3.0
173
+ version: 2.2.0
174
174
  type: :runtime
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: 0.3.0
180
+ version: 2.2.0
181
+ - !ruby/object:Gem::Dependency
182
+ name: shale
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 1.0.0
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 1.0.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: phlex
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: 1.8.1
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: 1.8.1
181
209
  - !ruby/object:Gem::Dependency
182
210
  name: kramdown
183
211
  requirement: !ruby/object:Gem::Requirement
@@ -277,13 +305,9 @@ files:
277
305
  - lib/yarrow/console_runner.rb
278
306
  - lib/yarrow/content/expansion/aggregator.rb
279
307
  - lib/yarrow/content/expansion/basename_merge.rb
280
- - lib/yarrow/content/expansion/directory_map.rb
281
308
  - lib/yarrow/content/expansion/directory_merge.rb
282
- - lib/yarrow/content/expansion/file_list.rb
283
309
  - lib/yarrow/content/expansion/filename_map.rb
284
- - lib/yarrow/content/expansion/strategy.rb
285
310
  - lib/yarrow/content/expansion/traversal.rb
286
- - lib/yarrow/content/expansion/tree.rb
287
311
  - lib/yarrow/content/graph.rb
288
312
  - lib/yarrow/content/model.rb
289
313
  - lib/yarrow/content/policy.rb
@@ -1,21 +0,0 @@
1
- module Yarrow
2
- module Content
3
- module Expansion
4
- class DirectoryMap < Aggregator
5
- def expand_source(container, policy)
6
- puts "create_node label=:collection type=:#{policy.container} name='#{container.props[:basename]}'"
7
- @current_collection = container.props[:basename]
8
- end
9
-
10
- def expand_directory(collection, policy)
11
- puts "create_node label=:collection type=:#{policy.collection} name='#{collection.props[:basename]}' collection=#{@current_collection}"
12
- @current_collection = collection.props[:basename]
13
- end
14
-
15
- def expand_file(entity, policy)
16
- puts "create_node label=:entity type=:#{policy.entity} name='#{entity.props[:basename]}' collection='#{@current_collection}"
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,15 +0,0 @@
1
- module Yarrow
2
- module Content
3
- module Expansion
4
- class FileList < Strategy
5
- def expand(policy)
6
- start_node = graph.n(:root).out(name: policy.container.to_s)
7
-
8
- start_node.out(:files).each do |file_node|
9
-
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,118 +0,0 @@
1
- module Yarrow
2
- module Content
3
- module Expansion
4
- class Strategy
5
- include Yarrow::Tools::FrontMatter
6
-
7
- attr_reader :graph
8
-
9
- def initialize(graph)
10
- @graph = graph
11
- @subcollections = {}
12
- @entity_links = []
13
- @index_links = []
14
- @index = nil
15
- end
16
-
17
- # Expand a directory to a collection node representing a collection of entities
18
- def expand_directory(policy, node)
19
- index = graph.create_node do |collection_node|
20
-
21
- collection_attrs = {
22
- name: node.props[:name],
23
- title: node.props[:name].capitalize,
24
- body: ""
25
- }
26
-
27
- populate_collection(collection_node, policy, collection_attrs)
28
- end
29
-
30
- # Add this collection id to the lookup table for edge construction
31
- @subcollections[node.props[:path]] = index
32
-
33
- # Join the collection to its parent
34
- unless node.props[:slug] == policy.collection.to_s || !@subcollections.key?(node.props[:entry].parent.to_s)
35
- graph.create_edge do |edge|
36
- edge.label = :child
37
- edge.from = @subcollections[node.props[:entry].parent.to_s].id
38
- edge.to = index.id
39
- end
40
- end
41
- end
42
-
43
- # Extract collection level configuration/metadata from the root node for
44
- # this content type.
45
- def extract_metadata(node, type)
46
- # TODO: support _index or _slug convention as well
47
- meta_file = node.out(slug: type.to_s).first
48
-
49
- if meta_file
50
- # Process metadata and add it to the collection node
51
- # TODO: pass in content converter object
52
- # TODO: index/body content by default if extracted from frontmatter
53
- body, data = process_content(meta_file.props[:entry])
54
- else
55
- # Otherwise, assume default collection behaviour
56
- data = {}
57
- end
58
-
59
- # Generate a default title if not provided in metadata
60
- unless data.key?(:title)
61
- data[:title] = type.to_s.capitalize
62
- end
63
-
64
- data
65
- end
66
-
67
- def populate_collection(node, policy, meta_attrs)
68
- node.label = :collection
69
- node.props[:type] = policy.collection
70
- node.props[:resource] = policy.collection_const.new(meta_attrs)
71
- end
72
-
73
- def populate_entity(node, policy, meta_attrs)
74
- node.label = :item
75
- node.props[:type] = policy.entity
76
- node.props[:resource] = policy.entity_const.new(meta_attrs)
77
- end
78
-
79
- def merge_collection_index(node, policy, meta_attrs)
80
- props = { resource: node.props[:resource].merge(meta_attrs) }
81
- node.merge_props(props)
82
- end
83
-
84
- # Workaround for handling meta and content source in multiple files or a single
85
- # file with front matter.
86
- def process_content(path)
87
- case path.extname
88
- when '.htm', '.md'
89
- read_split_content(path.to_s, symbolize_keys: true)
90
- # when '.md'
91
- # body, data = read_split_content(path.to_s, symbolize_keys: true)
92
- # [Kramdown::Document.new(body).to_html, data]
93
- when '.yml'
94
- [nil, YAML.load(File.read(path.to_s), symbolize_names: true)]
95
- end
96
- # TODO: Raise error if unsupported extname reaches here
97
- end
98
-
99
- def connect_expanded_entities
100
- # Once all files and directories have been expanded, connect all the child
101
- # edges between collections and entities
102
- @entity_links.each do |entity_link|
103
- graph.create_edge do |edge|
104
- edge.label = :child
105
- edge.from = entity_link[:parent_id].id
106
- edge.to = entity_link[:child_id].id
107
- end
108
- end
109
-
110
- # Merge index page body and metadata with their parent collections
111
- @index_links.each do |index_link|
112
- merge_collection_index(index_link[:parent_id], policy, index_link[:index_attrs])
113
- end
114
- end
115
- end
116
- end
117
- end
118
- end
@@ -1,93 +0,0 @@
1
- module Yarrow
2
- module Content
3
- module Expansion
4
- class Tree < Strategy
5
- def expand(policy)
6
- # If match path represents entire content dir, then include the entire
7
- # content dir instead of scanning from a subfolder matching the name of
8
- # the collection.
9
- #start_node = if policy.match_path == "."
10
- start_node = if policy.match_path == "."
11
- # TODO: match against source_dir
12
- graph.n(:root).out(:directory)
13
- else
14
- graph.n(name: policy.match_path)
15
- end
16
-
17
- # Collect all nested collections in the subgraph for this content type
18
- @subcollections = {}
19
- @entity_links = []
20
- @index_links = []
21
- @index = nil
22
-
23
- # Scan and collect all nested files from the root
24
- start_node.depth_first.each do |node|
25
- if node.label == :directory
26
- expand_directory(policy, node)
27
- elsif node.label == :file
28
- expand_file_by_extension(policy, node)
29
- end
30
- end
31
-
32
- # Once all files and directories have been expanded, connect all the child
33
- # edges between collections and entities
34
- @entity_links.each do |entity_link|
35
- graph.create_edge do |edge|
36
- edge.label = :child
37
- edge.from = entity_link[:parent_id].id
38
- edge.to = entity_link[:child_id].id
39
- end
40
- end
41
-
42
- # Merge index page body and metadata with their parent collections
43
- @index_links.each do |index_link|
44
- merge_collection_index(index_link[:parent_id], policy, index_link[:index_attrs])
45
- end
46
- end
47
-
48
- def expand_file_by_basename(policy, node)
49
- body, meta = process_content(node.props[:entry])
50
- meta = {} if !meta
51
-
52
-
53
- end
54
-
55
- def expand_file_by_extension(policy, node)
56
- body, meta = process_content(node.props[:entry])
57
- meta = {} if !meta
58
-
59
- # TODO: document mapping convention for index pages and collection metadata
60
- # TODO: underscore _index pattern?
61
- bare_basename = node.props[:entry].basename(node.props[:entry].extname)
62
- if bare_basename.to_s == "index"
63
- @index_links << {
64
- parent_id: @subcollections[node.props[:entry].parent.to_s],
65
- index_attrs: meta.merge({ body: body})
66
- }
67
- else
68
- # Create an entity node representing a file mapped to a unique content object
69
- entity = graph.create_node do |entity_node|
70
-
71
- entity_slug = node.props[:entry].basename(node.props[:entry].extname).to_s
72
-
73
- entity_attrs = {
74
- name: entity_slug,
75
- title: entity_slug.gsub("-", " ").capitalize,
76
- body: body
77
- }
78
-
79
- populate_entity(entity_node, policy, entity_attrs.merge(meta || {}))
80
- end
81
-
82
- # We may not have an expanded node for the parent collection if this is a
83
- # preorder traversal so save it for later
84
- @entity_links << {
85
- parent_id: @subcollections[node.props[:entry].parent.to_s],
86
- child_id: entity
87
- }
88
- end
89
- end
90
- end
91
- end
92
- end
93
- end