lowload 0.5.0 → 0.6.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: ff485e94bc43e900c70c84618b8291a7f329f65f5c77f800e4f63441abea255a
4
- data.tar.gz: a0791c307b326183ad64da9a094e2591e368edd1871b075eff8432cef79a8467
3
+ metadata.gz: 47cc7e9bc1bf7d856e12c1a91d6cd4ab388a973d73bb8fb7d2a8498ea3631cf4
4
+ data.tar.gz: '04864e7a3f9ab0644ebf3356095369859eb025f19087892f3c86b5b54bba35ed'
5
5
  SHA512:
6
- metadata.gz: 3a91ef3b898d28435381872dfe19589699ab7fe396969780001d4c5d27e144518cd3cb5eb9165ebb3e46c5149a28fd2d511b698f3beb760e95d58fe45a0b0ef9
7
- data.tar.gz: fee30da0af61c8160415a6017a9baac910fb529ecb66239b4198c1a068d58054372e8fb00df64823cd6b4a335c4754919fda61a3316b9a471ea26b6ac301ea4c
6
+ metadata.gz: 81e0d64d2f3ab72619663d2f6649c8affe284fe106989aad6c98dd5d7d760b5407f28171af96447c241c55e86cd444fef9f7702b748a35bab1dfa77c408c2497
7
+ data.tar.gz: fed385baed2a6d64c26051f34d42e24d022a78823cbd128790c4cfa90e82b32a07576edb475e3c89c2942dc9950b267d2311b8fa718b81247bd5e063dfda5e80
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LowLoad
4
+ class Adapter
5
+ EXTENSIONS = []
6
+
7
+ def metadata(file_path:)
8
+ end
9
+
10
+ def preload(file_path:)
11
+ end
12
+
13
+ def evaluate(file_path:, top_level_binding: nil)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'lowkey'
5
+ require_relative 'adapter'
6
+
7
+ module LowLoad
8
+ class MarkdownAdapter < Adapter
9
+ EXTENSIONS = ['md', 'rd', 'markdown', 'raindown']
10
+
11
+ def metadata(file_path:)
12
+ meta_lines = []
13
+ yaml_lines = []
14
+
15
+ File.foreach(file_path).with_index do |line, index|
16
+ if line.strip == '---'
17
+ meta_lines << index + 1
18
+ break if meta_lines.count > 1
19
+ else
20
+ yaml_lines << line
21
+ end
22
+ end
23
+
24
+ YAML.safe_load(yaml_lines.join, symbolize_names: true)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lowkey'
4
+ require_relative 'adapter'
5
+ require_relative '../loader'
6
+
7
+ def top_level_binding
8
+ binding
9
+ end
10
+
11
+ module LowLoad
12
+ class RBXAdapter < Adapter
13
+ EXTENSIONS = ['rbx']
14
+
15
+ # Map all definitions and dependencies.
16
+ def metadata(file_path:)
17
+ Lowkey.load(file_path)
18
+
19
+ { file_path: }
20
+ end
21
+
22
+ # Then autoload all dependencies for those files.
23
+ def preload(file_path:)
24
+ Loader.add_autoloads(file_proxy: Lowkey[file_path])
25
+ end
26
+
27
+ # Now we can load the file into Ruby.
28
+ def evaluate(file_path:)
29
+ # 1. "File Load" phase.
30
+ file_proxy = Lowkey[file_path] || Lowkey.load(file_path)
31
+ templates = wrap_render_methods(file_proxy:)
32
+
33
+ # 2. "Class Load" phase.
34
+ # Not a security risk because "eval" is equivalent to "load" or "require_relative" in this context.
35
+ eval(file_proxy.export, top_level_binding, file_proxy.file_path, 0) # rubocop:disable Security/Eval
36
+
37
+ # 3. "Runtime" phase (before low nodes are rendered).
38
+ # Templates only exist if antlers gem has been required by another gem (such as LowNode) and the template contains antlers syntax.
39
+ templates.each do |namespace, method_template|
40
+ klass = Object.const_get(namespace)
41
+ method, template = method_template
42
+ # TODO: If params contain "**props" or similar then send that, so that LowNode can replicate it.
43
+ params = method.params.map(&:name)
44
+
45
+ next unless supports_templates?(klass) || raise(UnsupportedTemplate, "Template for '#{namespace}' identified but not implemented")
46
+
47
+ # TODO: Make template engine configurable.
48
+ klass.build_template(template:, params:, engine: Antlers, namespace:)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def supports_templates?(klass)
55
+ klass.respond_to?(:render) && klass.respond_to?(:template) && klass.respond_to?(:build_template)
56
+ end
57
+
58
+ def wrap_render_methods(file_proxy:)
59
+ # GOAL: Templates could be organised by method and template rendering engine.
60
+ templates = {}
61
+
62
+ file_proxy.definitions.each_value do |class_proxy|
63
+ render_method = class_proxy.respond_to?(:instance_methods) ? class_proxy.instance_methods[:render] : nil
64
+
65
+ next unless render_method
66
+
67
+ render_method_body = render_method.body.export
68
+
69
+ if defined?(Antlers) && ['{', '<{'].any? { |needle| render_method_body.include?(needle) }
70
+ templates[class_proxy.namespace] = [render_method, render_method_body]
71
+ end
72
+
73
+ # Intended to target HTML or Antlers tags. Use HEREDOC "<<~" in a plain Ruby (".rb") file, not RBX.
74
+ render_method.body.wrap(prefix: '%q{', suffix: '}') if render_method_body.strip.start_with?('<')
75
+ end
76
+
77
+ templates
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lowkey'
4
+ require_relative 'adapter'
5
+ require_relative '../loader'
6
+
7
+ module LowLoad
8
+ class RubyAdapter < Adapter
9
+ EXTENSIONS = ['rb']
10
+
11
+ # Map all definitions and dependencies.
12
+ def metadata(file_path:)
13
+ Lowkey.load(file_path)
14
+
15
+ { file_path: }
16
+ end
17
+
18
+ # Then autoload all dependencies for those files.
19
+ def preload(file_path:)
20
+ Loader.add_autoloads(file_proxy: Lowkey[file_path])
21
+ end
22
+
23
+ # Now we can load the file into Ruby.
24
+ def evaluate(file_path:)
25
+ load(file_path)
26
+ end
27
+ end
28
+ end
data/lib/lowload.rb CHANGED
@@ -1,99 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'antlers'
4
- require 'lowkey'
5
-
3
+ require_relative 'adapters/markdown_adapter'
4
+ require_relative 'adapters/rbx_adapter'
5
+ require_relative 'adapters/ruby_adapter'
6
6
  require_relative 'loader'
7
-
8
- def top_level_binding
9
- binding
10
- end
7
+ require_relative 'metadata'
11
8
 
12
9
  module LowLoad
10
+ class UnsupportedFileType < StandardError; end
13
11
  class UnsupportedTemplate < StandardError; end
14
12
 
15
13
  class << self
16
- # Files are mapped, autoloaded, then loaded into Ruby in 3 separate stages.
14
+ ADAPTERS = [MarkdownAdapter.new, RBXAdapter.new, RubyAdapter.new]
15
+
17
16
  def dirload(path, pwd = Dir.pwd)
18
17
  absolute_path = File.expand_path(path, pwd)
19
- file_paths = Dir["#{absolute_path}/**/*"]
18
+ file_paths = Dir["#{absolute_path}/**/*"].filter { !File.directory?(it) }
20
19
 
21
- # Map all definitions and dependencies first.
22
- file_paths.each do |file_path|
23
- Lowkey.load(file_path)
20
+ file_path_adapters = file_paths.each_with_object({}) do |file_path, hash|
21
+ hash[file_path] = find_adapter(file_path:)
24
22
  end
25
23
 
26
- # Then autoload all dependencies for those files.
27
- file_paths.each do |file_path| # rubocop:disable Style/CombinableLoops
28
- Loader.add_autoloads(file_proxy: Lowkey[file_path])
29
- end
24
+ metadata = Metadata.new
25
+ metadata.process(file_path_adapters:)
26
+ step(:preload, file_path_adapters:)
27
+ step(:evaluate, file_path_adapters:)
30
28
 
31
- # Now we can load the files into Ruby.
32
- file_paths.each do |file_path| # rubocop:disable Style/CombinableLoops
33
- lowload(file_path)
34
- end
29
+ metadata
35
30
  end
36
31
 
37
- # Dependencies must first be loaded by dirload() or required by the file.
38
32
  def lowload(file_path)
39
- case File.extname(file_path).delete_prefix('.')
40
- when 'rb'
41
- load(file_path)
42
- when 'rbx'
43
- load_rbx(file_path)
44
- end
45
- end
46
-
47
- private
48
-
49
- def load_rbx(file_path)
50
- # 1. "File Load" phase.
51
- file_proxy = Lowkey[file_path] || Lowkey.load(file_path)
52
- templates = wrap_render_methods(file_proxy:)
53
-
54
- # 2. "Class Load" phase.
55
- # Not a security risk because "eval" is equivalent to "load" or "require_relative" in this context.
56
- eval(file_proxy.export, top_level_binding, file_proxy.file_path, 0) # rubocop:disable Security/Eval
33
+ adapter = find_adapter(file_path:)
57
34
 
58
- # 3. "Runtime" phase (before LowNode instances are rendered).
59
- # Templates only exist if antlers gem has been required by another gem (such as LowNode) and the template contains antlers syntax.
60
- templates.each do |namespace, method_template|
61
- klass = const_get(namespace)
62
- method, template = method_template
63
- # TODO: If params contain "**props" or similar then send that, so that LowNode can replicate it.
64
- params = method.params.map(&:name)
35
+ raise(UnsupportedFileType, "Could not load #{file_path}") if adapter.nil?
65
36
 
66
- next unless supports_templates?(klass) || raise(UnsupportedTemplate, "Template for '#{namespace}' identified but not implemented")
67
-
68
- # TODO: Make template engine configurable.
69
- klass.build_template(template:, params:, engine: Antlers, namespace:)
70
- end
37
+ adapter.evaluate(file_path:)
71
38
  end
72
39
 
73
- def supports_templates?(klass)
74
- klass.respond_to?(:render) && klass.respond_to?(:template) && klass.respond_to?(:build_template)
75
- end
76
-
77
- def wrap_render_methods(file_proxy:)
78
- # GOAL: Templates could be organised by method and template rendering engine.
79
- templates = {}
80
-
81
- file_proxy.definitions.each_value do |class_proxy|
82
- render_method = class_proxy.respond_to?(:instance_methods) ? class_proxy.instance_methods[:render] : nil
83
-
84
- next unless render_method
85
-
86
- render_method_body = render_method.body.export
87
-
88
- if defined?(Antlers) && ['{', '<{'].any? { |needle| render_method_body.include?(needle) }
89
- templates[class_proxy.namespace] = [render_method, render_method_body]
90
- end
91
-
92
- # Intended to target HTML or Antlers tags. Use HEREDOC "<<~" in a plain Ruby (".rb") file, not RBX.
93
- render_method.body.wrap(prefix: '%q{', suffix: '}') if render_method_body.strip.start_with?('<')
40
+ def step(step, file_path_adapters:)
41
+ file_path_adapters.each do |file_path, adapter|
42
+ adapter&.send(step, file_path:)
94
43
  end
44
+ end
95
45
 
96
- templates
46
+ def find_adapter(file_path:)
47
+ extension = File.extname(file_path).delete_prefix('.')
48
+ ADAPTERS.find { |adapter| adapter.class::EXTENSIONS.include?(extension) }
97
49
  end
98
50
  end
99
51
  end
data/lib/metadata.rb ADDED
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'adapters/markdown_adapter'
4
+
5
+ module LowLoad
6
+ class Metadata
7
+ EXTENSIONS = [
8
+ *::LowLoad::MarkdownAdapter::EXTENSIONS,
9
+ *::LowLoad::RBXAdapter::EXTENSIONS,
10
+ *::LowLoad::RubyAdapter::EXTENSIONS,
11
+ ]
12
+
13
+ attr_accessor :file_paths, :file_types, :tags
14
+
15
+ def initialize
16
+ @file_paths = []
17
+
18
+ @file_types = EXTENSIONS.each_with_object({}) do |extension, hash|
19
+ hash[extension] = []
20
+ end
21
+
22
+ @tags = {}
23
+ end
24
+
25
+ def process(file_path_adapters:)
26
+ file_path_adapters.each do |file_path, adapter|
27
+ if (metadata = adapter&.metadata(file_path:))
28
+ metadata.merge!({
29
+ file_path:,
30
+ file_type: File.extname(file_path).delete_prefix('.'),
31
+ file_loaded: true,
32
+ })
33
+ else
34
+ metadata = { file_loaded: false }
35
+ end
36
+
37
+ append(metadata:)
38
+ end
39
+ end
40
+
41
+ def append(metadata:)
42
+ @file_paths << metadata[:file_path]
43
+ @file_types[metadata[:file_type]] = metadata[:file_path]
44
+
45
+ metadata[:tags]&.each do |tag|
46
+ @tags[tag] ||= []
47
+ @tags[tag] = metadata[:file_path]
48
+ end
49
+ end
50
+ end
51
+ end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LowLoad
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lowload
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
@@ -31,8 +31,13 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
+ - lib/adapters/adapter.rb
35
+ - lib/adapters/markdown_adapter.rb
36
+ - lib/adapters/rbx_adapter.rb
37
+ - lib/adapters/ruby_adapter.rb
34
38
  - lib/loader.rb
35
39
  - lib/lowload.rb
40
+ - lib/metadata.rb
36
41
  - lib/version.rb
37
42
  homepage: https://github.com/low-rb/lowload
38
43
  licenses: []
@@ -53,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
58
  - !ruby/object:Gem::Version
54
59
  version: '0'
55
60
  requirements: []
56
- rubygems_version: 4.0.10
61
+ rubygems_version: 4.0.6
57
62
  specification_version: 4
58
63
  summary: An autoloader without namespace and folder structure conventions
59
64
  test_files: []