syntropy 0.13.1 → 0.14

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: dad58d19dc755d1a8ea6adb32cd7146b2228b5ace655a01b2e7932fd8abb7d23
4
- data.tar.gz: 228678e0a76e67b012e52c89f5ed90c3d08e884a6424c0c51fcf9f840b2e6876
3
+ metadata.gz: bc595fea6260cf92c377aeb6931cd1f62ce02fd2e05ca2436fb8b49ac57e4b49
4
+ data.tar.gz: 9c38f08bf13033aabc5bcf4df9b96e05e238461a43513167b6aeca21fb55c388
5
5
  SHA512:
6
- metadata.gz: 5ea7c453ae3e32d17f4bc35204fcf4c29f4eae7d95e9232f56b6ff65dcfaab9f3f6e41fb5562817ab3d3bd10a3ee2e5c92c440045bbdc8a51bc88d155fac7ab4
7
- data.tar.gz: fb28a9011ea58505b9923589b62f0010eb97dea9f1df81e4c0483682669715c455fff5a150888f06f117e127497a98e7c93535f683d924e86ffcfeb007cf9fc5
6
+ metadata.gz: 23d2888d82b16a4f848523193478d7e2813398cf07b32a5ef009c2ce24d76b150579228b32abf6179176075e882e6c68119002819e945984207f611c68726a43
7
+ data.tar.gz: 13416d8be55de9b6fc454c7c99e25ad65093be329de19b9e4c561ab28e1436f412d8e42838ec14ad3ab039b79b0d57c3b0ea157c5fbb2795d97d605dc2f34b63
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # 0.14 2025-08-30
2
+
3
+ - Tweak "boot" sequence
4
+ - Update dependencies
5
+ - Log errors in App#call
6
+ - Improve module loading, add logging
7
+
1
8
  # 0.13 2025-08-28
2
9
 
3
10
  - Reimplement module loading
data/TODO.md CHANGED
@@ -1,3 +1,28 @@
1
+ - [ ] Collection - treat directories and files as collections of data.
2
+
3
+ Kind of similar to the routing tree, but instead of routes it just takes a
4
+ bunch of files and turns it into a dataset. Each directory is a "table" and is
5
+ composed of zero or more files that form rows in the table. Supported file
6
+ formats:
7
+
8
+ - foo.md - markdown with optional front matter
9
+ - foo.json - JSON record
10
+ - foo.yml - YAML record
11
+
12
+ API:
13
+
14
+ ```ruby
15
+ Articles = @app.collection('_articles/*.md')
16
+ article = Articles.last_by(&:date)
17
+
18
+ article.title #=>
19
+ article.date #=>
20
+ article.layout #=>
21
+ article.render_proc #=> (load layout, apply article)
22
+ article.render #=> (render to HTML)
23
+ ...
24
+ ```
25
+
1
26
  - [ ] Improve serving of static files:
2
27
  - [ ] support for compression
3
28
  - [ ] support for caching headers
data/bin/syntropy CHANGED
@@ -4,7 +4,7 @@
4
4
  require 'syntropy'
5
5
  require 'optparse'
6
6
 
7
- opts = {
7
+ env = {
8
8
  mount_path: '/',
9
9
  banner: Syntropy::BANNER,
10
10
  logger: true
@@ -15,17 +15,17 @@ parser = OptionParser.new do |o|
15
15
 
16
16
  o.on('-b', '--bind BIND', String,
17
17
  'Bind address (default: http://0.0.0.0:1234). You can specify this flag multiple times to bind to multiple addresses.') do
18
- opts[:bind] ||= []
19
- opts[:bind] << it
18
+ env[:bind] ||= []
19
+ env[:bind] << it
20
20
  end
21
21
 
22
22
  o.on('-s', '--silent', 'Silent mode') do
23
- opts[:banner] = nil
24
- opts[:logger] = nil
23
+ env[:banner] = nil
24
+ env[:logger] = nil
25
25
  end
26
26
 
27
27
  o.on('-w', '--watch', 'Watch for changed files') do
28
- opts[:watch_files] = 0.1
28
+ env[:watch_files] = 0.1
29
29
  end
30
30
 
31
31
  o.on('-h', '--help', 'Show this help message') do
@@ -34,7 +34,7 @@ parser = OptionParser.new do |o|
34
34
  end
35
35
 
36
36
  o.on('-m', '--mount', 'Set mount path (default: /)') do
37
- opts[:mount_path] = it
37
+ env[:mount_path] = it
38
38
  end
39
39
 
40
40
  o.on('-v', '--version', 'Show version') do
@@ -54,17 +54,20 @@ rescue StandardError => e
54
54
  exit
55
55
  end
56
56
 
57
- opts[:root_dir] = ARGV.shift || '.'
57
+ env[:root_dir] = ARGV.shift || '.'
58
58
 
59
- if !File.directory?(opts[:root_dir])
60
- puts "#{File.expand_path(opts[:root_dir])} Not a directory"
59
+ if !File.directory?(env[:root_dir])
60
+ puts "#{File.expand_path(env[:root_dir])} Not a directory"
61
61
  exit
62
62
  end
63
63
 
64
+ puts env[:banner] if env[:banner]
65
+ env[:banner] = false
66
+
64
67
 
65
68
  # We set Syntropy.machine so we can reference it from anywhere
66
- opts[:machine] = Syntropy.machine = UM.new
67
- opts[:logger] = opts[:logger] && TP2::Logger.new(opts[:machine], **opts)
69
+ env[:machine] = Syntropy.machine = UM.new
70
+ env[:logger] = env[:logger] && TP2::Logger.new(env[:machine], **env)
68
71
 
69
- app = Syntropy::App.load(opts)
70
- TP2.run(opts) { app.call(it) }
72
+ app = Syntropy::App.load(env)
73
+ TP2.run(env) { app.call(it) }
data/lib/syntropy/app.rb CHANGED
@@ -15,38 +15,38 @@ require 'syntropy/routing_tree'
15
15
  module Syntropy
16
16
  class App
17
17
  class << self
18
- def load(opts)
19
- site_file_app(opts) || default_app(opts)
18
+ def load(env)
19
+ site_file_app(env) || default_app(env)
20
20
  end
21
21
 
22
22
  private
23
23
 
24
24
  # for apps with a _site.rb file
25
- def site_file_app(opts)
26
- fn = File.join(opts[:root_dir], '_site.rb')
25
+ def site_file_app(env)
26
+ fn = File.join(env[:root_dir], '_site.rb')
27
27
  return nil if !File.file?(fn)
28
28
 
29
- loader = Syntropy::ModuleLoader.new(opts)
29
+ loader = Syntropy::ModuleLoader.new(env)
30
30
  loader.load('_site')
31
31
  end
32
32
 
33
33
  # default app
34
- def default_app(opts)
35
- new(**opts)
34
+ def default_app(env)
35
+ new(**env)
36
36
  end
37
37
  end
38
38
 
39
- attr_reader :module_loader, :routing_tree, :root_dir, :mount_path, :opts
39
+ attr_reader :module_loader, :routing_tree, :root_dir, :mount_path, :env
40
40
 
41
- def initialize(**opts)
42
- @machine = opts[:machine]
43
- @root_dir = opts[:root_dir]
44
- @mount_path = opts[:mount_path]
45
- @opts = opts
41
+ def initialize(**env)
42
+ @machine = env[:machine]
43
+ @root_dir = File.expand_path(env[:root_dir])
44
+ @mount_path = env[:mount_path]
45
+ @env = env
46
46
 
47
- @module_loader = Syntropy::ModuleLoader.new(app: self, **opts)
47
+ @module_loader = Syntropy::ModuleLoader.new(app: self, **env)
48
48
  setup_routing_tree
49
- start_app
49
+ start
50
50
  end
51
51
 
52
52
  # Processes an incoming HTTP request. Requests are processed by first
@@ -70,8 +70,11 @@ module Syntropy
70
70
  proc = route[:proc] ||= compute_route_proc(route)
71
71
  proc.(req)
72
72
  rescue StandardError => e
73
- # p e
74
- # p e.backtrace
73
+ @env[:logger]&.error(
74
+ message: "Error while serving request",
75
+ method: req.method,
76
+ path: req.path
77
+ )
75
78
  error_handler = get_error_handler(route)
76
79
  error_handler.(req, e)
77
80
  end
@@ -84,7 +87,7 @@ module Syntropy
84
87
  # @return [void]
85
88
  def setup_routing_tree
86
89
  @routing_tree = Syntropy::RoutingTree.new(
87
- root_dir: @root_dir, mount_path: @mount_path, **@opts
90
+ root_dir: @root_dir, mount_path: @mount_path, **@env
88
91
  )
89
92
  @router_proc = @routing_tree.router_proc
90
93
  end
@@ -138,7 +141,7 @@ module Syntropy
138
141
  end
139
142
 
140
143
  def render_markdown(route)
141
- atts, md = Syntropy.parse_markdown_file(route[:target][:fn], @opts)
144
+ atts, md = Syntropy.parse_markdown_file(route[:target][:fn], @env)
142
145
 
143
146
  if (layout = atts[:layout])
144
147
  route[:applied_layouts] ||= {}
@@ -277,15 +280,17 @@ module Syntropy
277
280
  # watcher according to app options.
278
281
  #
279
282
  # @return [void]
280
- def start_app
283
+ def start
281
284
  @machine.spin do
282
285
  # we do startup stuff asynchronously, in order to first let TP2 do its
283
286
  # setup tasks
284
287
  @machine.sleep 0.2
285
- @opts[:logger]&.info(
286
- message: "Serving from #{File.expand_path(@location)}"
288
+ route_count = @routing_tree.static_map.size + @routing_tree.dynamic_map.size
289
+ @env[:logger]&.info(
290
+ message: "Serving from #{@root_dir} (#{route_count} routes found)"
287
291
  )
288
- file_watcher_loop if opts[:watch_files]
292
+
293
+ file_watcher_loop if @env[:watch_files]
289
294
  end
290
295
  end
291
296
 
@@ -294,7 +299,7 @@ module Syntropy
294
299
  #
295
300
  # @return [void]
296
301
  def file_watcher_loop
297
- wf = @opts[:watch_files]
302
+ wf = @env[:watch_files]
298
303
  period = wf.is_a?(Numeric) ? wf : 0.1
299
304
  Syntropy.file_watch(@machine, @root_dir, period: period) do |event, fn|
300
305
  @module_loader.invalidate(fn)
@@ -14,7 +14,7 @@ module Syntropy
14
14
  #
15
15
  # @param path [String] file path
16
16
  # @return [Array] an tuple containing properties<Hash>, contents<String>
17
- def self.parse_markdown_file(path, opts)
17
+ def self.parse_markdown_file(path, env)
18
18
  content = IO.read(path) || ''
19
19
  atts = {}
20
20
 
@@ -30,9 +30,9 @@ module Syntropy
30
30
  atts = atts.merge(yaml)
31
31
  end
32
32
 
33
- if opts[:root_dir]
33
+ if env[:root_dir]
34
34
  atts[:url] = path
35
- .gsub(/#{opts[:root_dir]}/, '')
35
+ .gsub(/#{env[:root_dir]}/, '')
36
36
  .gsub(/\.md$/, '')
37
37
  end
38
38
 
@@ -32,7 +32,7 @@ module Syntropy
32
32
 
33
33
  code = IO.read(fn)
34
34
  env = @env.merge(module_loader: self, ref: ref)
35
- export_value = Syntropy::Module.load(env, code)
35
+ export_value = Syntropy::Module.load(env, code, fn)
36
36
  transform_module_export_value(export_value)
37
37
  end
38
38
 
@@ -51,10 +51,18 @@ module Syntropy
51
51
  end
52
52
 
53
53
  class Module
54
- def self.load(env, code)
54
+ def self.load(env, code, fn)
55
55
  m = new(**env)
56
- m.instance_eval(code)
57
- m.__export_value__
56
+ m.instance_eval(code, fn)
57
+ export_value = m.__export_value__
58
+ env[:logger]&.info(message: "Loaded module at #{fn}")
59
+ export_value
60
+ rescue StandardError => e
61
+ env[:logger]&.error(
62
+ message: "Error while loading module #{fn}",
63
+ error: e
64
+ )
65
+ raise
58
66
  end
59
67
 
60
68
  attr_reader
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Syntropy
4
- VERSION = '0.13.1'
4
+ VERSION = '0.14'
5
5
  end
data/syntropy.gemspec CHANGED
@@ -26,8 +26,8 @@ Gem::Specification.new do |s|
26
26
  s.add_dependency 'p2', '2.8'
27
27
  s.add_dependency 'papercraft', '1.4'
28
28
  s.add_dependency 'qeweney', '0.22'
29
- s.add_dependency 'tp2', '0.14.1'
30
- s.add_dependency 'uringmachine', '0.16'
29
+ s.add_dependency 'tp2', '0.15'
30
+ s.add_dependency 'uringmachine', '0.18'
31
31
 
32
32
  s.add_dependency 'listen', '3.9.0'
33
33
  s.add_dependency 'logger', '1.7.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syntropy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.1
4
+ version: '0.14'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -85,28 +85,28 @@ dependencies:
85
85
  requirements:
86
86
  - - '='
87
87
  - !ruby/object:Gem::Version
88
- version: 0.14.1
88
+ version: '0.15'
89
89
  type: :runtime
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - '='
94
94
  - !ruby/object:Gem::Version
95
- version: 0.14.1
95
+ version: '0.15'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: uringmachine
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - '='
101
101
  - !ruby/object:Gem::Version
102
- version: '0.16'
102
+ version: '0.18'
103
103
  type: :runtime
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - '='
108
108
  - !ruby/object:Gem::Version
109
- version: '0.16'
109
+ version: '0.18'
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: listen
112
112
  requirement: !ruby/object:Gem::Requirement