porous 0.1.0 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 764d087181654089e95897a26692efd6bf2b3302f36a1917695c9e5e7ba3c088
4
- data.tar.gz: 7eb52c0975ce2611e1e0b57591cd0da848c639a0873785a3e6023e3506852a18
3
+ metadata.gz: b55c1eaf688f84af5c848e212ab0f5686ca6d6f270a0ef68d35846824af0d716
4
+ data.tar.gz: 4ca350f60c41896911dba97cd62ec05437ede55ae11d0a6c1fd0e3a68a09281e
5
5
  SHA512:
6
- metadata.gz: 5ca6f72a3d234ca0e368da80f7c4c839fd6d80b5577ef3eca7df9f2c0788bbb3891a099bb62568eaa3357f3940c8e6c6cd65f5dfd42d25713cb85ea812696df7
7
- data.tar.gz: e16772a071f6cf91395774bac8b01374173624f5fff38e97539fbe3b72c6586538b2f716a851093cb46ee9aaa583ef1e713ed2baae042f305812ff14afd067ab
6
+ metadata.gz: a434473bf2ee80768ed88e729ecec2287af5a2596521e4fdb1857e82cff861eaeeba84ac9be5b6afba41340f6de543a7c57e1382e4a6d6e19e85960f0e6ea0c6
7
+ data.tar.gz: 5ddf2319739891025fac39dfc34d50a379f2403139f6171d95d2488eabf621b22dacad1266c9151af35242dff02210aef15ccc350d3b9f1c782c0c2d585f7a8b
data/.rubocop.yml CHANGED
@@ -1,13 +1,29 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 3.0
3
+ NewCops: enable
3
4
 
4
5
  Style/StringLiterals:
5
6
  Enabled: true
6
- EnforcedStyle: double_quotes
7
+ EnforcedStyle: single_quotes
7
8
 
8
9
  Style/StringLiteralsInInterpolation:
9
10
  Enabled: true
10
11
  EnforcedStyle: double_quotes
11
12
 
13
+ Style/Documentation:
14
+ Enabled: false
15
+
12
16
  Layout/LineLength:
13
17
  Max: 120
18
+
19
+ Metrics/BlockLength:
20
+ AllowedMethods:
21
+ - render
22
+ Metrics/MethodLength:
23
+ Max: 15
24
+ AllowedMethods:
25
+ - render
26
+
27
+ require:
28
+ - rubocop-rake
29
+ - rubocop-rspec
data/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@
7
7
  - Websockets support
8
8
  - Client-side hot reloading
9
9
 
10
+ ## [0.1.1] - 17 February 2024
11
+
12
+ - Server-side reloading
13
+
10
14
  ## [0.1.0] - 15 February 2024
11
15
 
12
16
  - `porous server` to run apps
data/README.md CHANGED
@@ -40,7 +40,7 @@ To start a new Porous project simply `gem install porous` using whichever Ruby e
40
40
 
41
41
  $ porous server
42
42
 
43
- By default Porous will run at `loclahost:9292`. Now you can edit `pages/home.rb` or add more pages. Finally restart the server and refresh the page. Hot-reloading will be coming later.
43
+ By default Porous will run at `loclahost:9292`. Now you can edit `pages/home.rb` or add more pages. Files you modify will be reloaded so you can simply refresh the page in your browser. Hot-reloading will be coming later once WebSockets support is implemented.
44
44
 
45
45
  ### Running examples
46
46
 
@@ -66,4 +66,4 @@ Everyone interacting in the Porous project's codebases, issue trackers, chat roo
66
66
 
67
67
  ## Acknowledgements
68
68
 
69
- The work done by Michał Kalbarczyk ([fazibear](https://github.com/fazibear)) on [Inesita](https://github.com/inesita-rb/inesita) and his [VirtualDOM wrapper](https://github.com/fazibear/opal-virtual-dom) which served as the starting point for my implementation of Porous.
69
+ I'd like to thank Michał Kalbarczyk ([fazibear](https://github.com/fazibear)) for his work done on [Inesita](https://github.com/inesita-rb/inesita) and his [VirtualDOM wrapper](https://github.com/fazibear/opal-virtual-dom) which served as the starting point for my implementation of Porous.
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require "rubocop/rake_task"
8
+ require 'rubocop/rake_task'
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
data/exe/porous CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require 'porous/cli'
3
5
 
4
6
  Porous::CLI.start ARGV
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  class CLI < Thor
3
5
  include Thor::Actions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  class CLI < Thor
3
5
  include Thor::Actions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  class CLI < Thor
3
5
  check_unknown_options!
@@ -18,9 +20,7 @@ module Porous
18
20
  desc: 'The host address Porous will bind to'
19
21
 
20
22
  def server
21
- Rackup::Server.start environment: 'development', builder: <<-BUILDER
22
- run Porous::Server.new
23
- BUILDER
23
+ Rackup::Server.start environment: 'development', builder: 'run Porous::Server.new'
24
24
  end
25
25
  end
26
26
  end
@@ -1,15 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Home
2
4
  include Porous::Page
3
5
  include Porous::Component
4
6
 
5
7
  def route = '/'
6
8
 
9
+ # rubocop:disable Metrics, Layout/LineLength
7
10
  def render
8
11
  div class: 'container p-8 mx-auto lg:h-full xl:px-0 flex flex-wrap' do
9
12
  div class: 'flex items-center w-full lg:w-1/2' do
10
13
  div class: 'max-w-2xl mb-8' do
11
14
  h1 class: 'text-4xl font-bold leading-snug tracking-tight text-gray-800 lg:text-4xl lg:leading-tight xl:text-6xl xl:leading-tight dark:text-white' do
12
- span class: "bg-gradient-to-br from-pink-500 to-violet-500 bg-clip-text text-transparent box-decoration-clone" do
15
+ span class: 'bg-gradient-to-br from-pink-500 to-violet-500 bg-clip-text text-transparent box-decoration-clone' do
13
16
  text 'Welcome to Porous!'
14
17
  end
15
18
  end
@@ -19,10 +22,10 @@ class Home
19
22
 
20
23
  div class: 'flex flex-col items-start space-y-3 sm:space-x-4 sm:space-y-0 sm:items-center sm:flex-row' do
21
24
  a href: 'https://github.com/exastencil/porous', target: '_blank', rel: 'noopener',
22
- class: "group relative inline-flex h-12 items-center justify-center overflow-hidden rounded-md bg-indigo-600 px-6 font-medium text-neutral-200 transition hover:scale-110" do
25
+ class: 'group relative inline-flex h-12 items-center justify-center overflow-hidden rounded-md bg-indigo-600 px-6 font-medium text-neutral-200 transition hover:scale-110' do
23
26
  span 'Get Started'
24
- div class: "absolute inset-0 flex h-full w-full justify-center [transform:skew(-12deg)_translateX(-100%)] group-hover:duration-1000 group-hover:[transform:skew(-12deg)_translateX(100%)]" do
25
- div class: "relative h-full w-8 bg-white/20"
27
+ div class: 'absolute inset-0 flex h-full w-full justify-center [transform:skew(-12deg)_translateX(-100%)] group-hover:duration-1000 group-hover:[transform:skew(-12deg)_translateX(100%)]' do
28
+ div class: 'relative h-full w-8 bg-white/20'
26
29
  end
27
30
  end
28
31
  a href: 'https://github.com/exastencil/porous', target: '_blank', rel: 'noopener',
@@ -45,4 +48,5 @@ class Home
45
48
  end
46
49
  end
47
50
  end
51
+ # rubocop:enable Metrics, Layout/LineLength
48
52
  end
data/lib/porous/cli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor'
2
4
 
3
5
  require 'porous'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Component
3
5
  module ClassMethods
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Component
3
5
  module Render
@@ -5,8 +7,7 @@ module Porous
5
7
  raise Error, "Implement #render in #{self.class} component"
6
8
  end
7
9
 
8
- def before_render
9
- end
10
+ def before_render; end
10
11
 
11
12
  def render_virtual_dom
12
13
  before_render
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Component
3
5
  module Virtual
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Component
3
5
  include VirtualDOM::DOM
@@ -15,7 +17,6 @@ module Porous
15
17
  init_injections
16
18
  inject
17
19
  @virtual_dom = render_virtual_dom
18
- self
19
20
  end
20
21
 
21
22
  def props
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Injection
3
5
  def init; end
@@ -21,15 +23,15 @@ module Porous
21
23
  def init_injections
22
24
  @injections ||= {}
23
25
  self.class.injections.each do |name, clazz|
24
- if clazz.included_modules.include?(Porous::Injection)
25
- @injections[name] = clazz
26
- .new
27
- .with_root_component(@root_component)
28
- else
26
+ unless clazz.included_modules.include?(Porous::Injection)
29
27
  raise Error, "Invalid #{clazz} class, should mixin Porous::Injection"
30
28
  end
29
+
30
+ @injections[name] = clazz
31
+ .new
32
+ .with_root_component(@root_component)
31
33
  end
32
- @injections.each do |key, instance|
34
+ @injections.each_value do |instance|
33
35
  instance.inject
34
36
  instance.init
35
37
  end
data/lib/porous/page.rb CHANGED
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Page
3
5
  # Define the route according to the Router::Routes rules
4
6
  def route!
5
7
  path = route
6
- @routes ||= Routes.new.tap do |routes|
8
+ @route ||= Routes.new.tap do |routes|
7
9
  routes.route path, to: self.class
8
10
  end
9
11
  end
data/lib/porous/router.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
- module Router
4
+ class Router
3
5
  include Porous::Component
4
6
 
5
7
  attr_reader :params
@@ -23,6 +25,10 @@ module Porous
23
25
  parse_url_params
24
26
  end
25
27
 
28
+ def routes
29
+ @routes.routes
30
+ end
31
+
26
32
  def self.included(base)
27
33
  base.extend(Porous::Component::ClassMethods)
28
34
  end
@@ -34,7 +40,8 @@ module Porous
34
40
 
35
41
  return @route = route
36
42
  end
37
- raise Error, "Can't find route for url"
43
+ available_routes = @routes.routes.map { |r| " #{r[:path]} => #{r[:component]}" }.join
44
+ raise InvalidRouteError, "Unknown route for: #{path}\n\nAvailable routes:\n\n#{available_routes}"
38
45
  end
39
46
 
40
47
  def find_component(route)
@@ -50,9 +57,9 @@ module Porous
50
57
  def call_on_enter_callback(route)
51
58
  return unless route[:on_enter]
52
59
 
53
- if route[:on_enter].respond_to?(:call)
54
- route[:on_enter].call
55
- end
60
+ return unless route[:on_enter].respond_to?(:call)
61
+
62
+ route[:on_enter].call
56
63
  end
57
64
 
58
65
  def go_to(path)
@@ -66,14 +73,16 @@ module Porous
66
73
 
67
74
  def parse_url_params
68
75
  @params = component_url_params
69
- query[1..-1].split('&').each do |param|
76
+ return if query.empty?
77
+
78
+ query[1..].split('&').each do |param|
70
79
  key, value = param.split('=')
71
80
  @params[key] = value
72
- end unless query.empty?
81
+ end
73
82
  end
74
83
 
75
84
  def component_url_params
76
- Hash[@route[:params].zip(path.match(@route[:regex])[1..-1])]
85
+ @route[:params].zip(path.match(@route[:regex])[1..]).to_h
77
86
  end
78
87
 
79
88
  def url_for(name, params = nil)
@@ -104,9 +113,9 @@ module Porous
104
113
 
105
114
  def url_with_params(route, params)
106
115
  path = route[:path]
107
- params.each do |key, value|
108
- path = path.gsub(":#{key}", "#{value}")
109
- end if params
116
+ params&.each do |key, value|
117
+ path = path.gsub(":#{key}", value.to_s)
118
+ end
110
119
  path
111
120
  end
112
121
  end
data/lib/porous/routes.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  class Routes
3
5
  attr_reader :routes
@@ -7,8 +9,9 @@ module Porous
7
9
  @routes = []
8
10
  end
9
11
 
12
+ # rubocop:disable Metrics/AbcSize
10
13
  def route(*params, &block)
11
- path = params.first.gsub(/^\//, '')
14
+ path = params.first.gsub(%r{^/}, '')
12
15
  path = @parent ? "#{@parent}/#{path}" : "/#{path}"
13
16
 
14
17
  add_subroutes(path, &block) if block_given?
@@ -19,12 +22,15 @@ module Porous
19
22
  add_route(params.last[:as], path, params.last[:to], params.last[:props], params.last[:on_enter])
20
23
  end
21
24
  end
25
+ # rubocop:enable Metrics/AbcSize
22
26
 
23
27
  def validate_component(component)
24
28
  raise Error, 'Component not exists' unless component
25
29
 
30
+ return if component.include?(Porous::Component)
31
+
26
32
  raise Error,
27
- "Invalid #{component} class, should mixin Porous::Component" unless component.include?(Porous::Component)
33
+ "Invalid #{component} class, should mixin Porous::Component"
28
34
  end
29
35
 
30
36
  def add_redirect(path, redirect_to)
@@ -51,6 +57,7 @@ module Porous
51
57
  @routes += subroutes.routes
52
58
  end
53
59
 
60
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
54
61
  def build_params_and_regex(path)
55
62
  regex = ['^']
56
63
  params = []
@@ -62,10 +69,10 @@ module Porous
62
69
  regex << '\/'
63
70
  case part[0]
64
71
  when ':'
65
- params << part[1..-1]
72
+ params << part[1..]
66
73
  regex << '([^\/]+)'
67
74
  when '*'
68
- params << part[1..-1]
75
+ params << part[1..]
69
76
  regex << '(.*)'
70
77
  break
71
78
  else
@@ -78,6 +85,7 @@ module Porous
78
85
  params: params
79
86
  }
80
87
  end
88
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
81
89
 
82
90
  def combine(other)
83
91
  @routes += other.routes
data/lib/porous/server.rb CHANGED
@@ -1,41 +1,66 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
- class Server
3
- class Router
4
- include Porous::Router
5
- end
4
+ class Application
5
+ include Porous::Component
6
6
 
7
- class Application
8
- include Porous::Component
9
-
10
- def render
11
- html do
12
- head do
13
- title do
14
- text props[:title]
15
- end
16
- meta charset: 'UTF-8'
17
- meta name: 'viewport', content: 'width=device-width, initial-scale=1.0'
18
- script src: 'https://cdn.tailwindcss.com'
7
+ def render
8
+ html do
9
+ head do
10
+ title do
11
+ text props[:title]
19
12
  end
13
+ meta charset: 'UTF-8'
14
+ meta name: 'viewport', content: 'width=device-width, initial-scale=1.0'
15
+ script src: 'https://cdn.tailwindcss.com'
16
+ end
20
17
 
21
- body class: 'bg-gray-50 dark:bg-gray-900' do
22
- component Router, props: { path: props[:path], query: props[:query] }
23
- end
18
+ body class: 'bg-gray-50 dark:bg-gray-900' do
19
+ component Porous::Router, props: { path: props[:path], query: props[:query] }
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ class Server
26
+ MONITORING = %w[components pages].freeze
27
+
28
+ def initialize(*_args)
29
+ @queue = Queue.new
30
+ start_live_reload
31
+ setup_rack_app
32
+ end
33
+
34
+ def start_live_reload
35
+ MONITORING.each { |path| FileUtils.mkdir_p path }
36
+ opts = {
37
+ only: /\.rb$/,
38
+ relative: true
39
+ }
40
+ @listener = Listen.to(*MONITORING, opts) do |modified, added, _removed|
41
+ (modified + added).each do |file|
42
+ load File.expand_path("#{Dir.pwd}/#{file}")
24
43
  end
44
+ setup_rack_app
25
45
  end
46
+ @listener.start
47
+ at_exit { @listener.stop }
26
48
  end
27
49
 
28
- def initialize(*args, &block)
50
+ def setup_rack_app
29
51
  @rack = Rack::Builder.new do
30
52
  use Rack::Static, urls: ['/static']
31
53
  run do |env|
32
- [
33
- 200,
34
- { 'content-type' => 'text/html' },
35
- [
36
- Application.new(title: 'Porous Web', path: env['PATH_INFO'], query: env['QUERY_STRING']).to_s
37
- ]
38
- ]
54
+ # Build a router to check for a valid route
55
+ Porous::Router.new path: env['PATH_INFO'], query: env['QUERY_STRING']
56
+ [200, { 'content-type' => 'text/html' },
57
+ [Application.new(title: 'Porous Web', path: env['PATH_INFO'], query: env['QUERY_STRING']).to_s]]
58
+ rescue Porous::InvalidRouteError => e
59
+ [404, { 'content-type' => 'text/plain' },
60
+ ["404 Page not found\n", e.message]]
61
+ rescue Porous::Error => e
62
+ [500, { 'content-type' => 'text/plain' },
63
+ ["500 Internal Server Error\n", e.message]]
39
64
  end
40
65
  end
41
66
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Porous
4
- VERSION = "0.1.0"
4
+ VERSION = '0.1.1'
5
5
  end
data/lib/porous.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'opal'
4
4
  require 'opal-browser'
5
- Opal.append_path File.expand_path('../../opal', __FILE__)
5
+ Opal.append_path File.expand_path('../opal', __dir__)
6
6
 
7
7
  require 'opal-virtual-dom'
8
8
  require 'listen'
@@ -27,4 +27,6 @@ end
27
27
  require 'porous/server'
28
28
 
29
29
  module Porous
30
+ class Error < StandardError; end
31
+ class InvalidRouteError < Error; end
30
32
  end
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VirtualDOM
2
4
  module DOM
3
- HTML_TAGS = %w(a abbr address area article aside audio b base bdi bdo big blockquote body br
5
+ HTML_TAGS = %w[a abbr address area article aside audio b base bdi bdo big blockquote body br
4
6
  button canvas caption cite code col colgroup data datalist dd del details dfn
5
7
  dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
6
8
  h6 head header hr html i iframe img input ins kbd keygen label legend li link
7
9
  main map mark menu menuitem meta meter nav noscript object ol optgroup option
8
10
  output p param picture pre progress q rp rt ruby s samp script section select
9
11
  small source span strong style sub summary sup table tbody td textarea tfoot th
10
- thead time title tr track u ul var video wbr)
12
+ thead time title tr track u ul var video wbr].freeze
11
13
 
12
- SVG_TAGS = %w(svg path)
14
+ SVG_TAGS = %w[svg path].freeze
13
15
 
14
16
  (HTML_TAGS + SVG_TAGS).each do |tag|
15
17
  define_method tag do |params = {}, &block|
@@ -38,7 +40,8 @@ module VirtualDOM
38
40
  self
39
41
  end
40
42
 
41
- def method_missing(clazz, params = {}, &block)
43
+ # rubocop:disable Style/MissingRespondToMissing, Metrics/MethodLength, Metrics/AbcSize
44
+ def method_missing(klass, params = {}, &block)
42
45
  return unless @__last_virtual_node__
43
46
  return unless @__virtual_nodes__
44
47
 
@@ -51,28 +54,29 @@ module VirtualDOM
51
54
  end
52
55
 
53
56
  class_params = @__last_virtual_node__.params.delete(:className)
54
- method_params = if clazz.end_with?('!')
57
+ method_params = if klass.end_with?('!')
55
58
  { id: clazz[0..-2],
56
59
  class: merge_string(class_params, params[:class]) }
57
60
  else
58
- { class: merge_string(class_params, params[:class], clazz.gsub('_', '-').gsub('--', '_')) }
61
+ { class: merge_string(class_params, params[:class], klass.gsub('_', '-').gsub('--', '_')) }
59
62
  end
60
63
  params = @__last_virtual_node__.params.merge(params).merge(method_params)
61
64
  process_tag(@__last_virtual_node__.name, params, block, children)
62
65
  end
66
+ # rubocop:enable Style/MissingRespondToMissing, Metrics/MethodLength, Metrics/AbcSize
63
67
 
64
68
  def merge_string(*params)
65
69
  arr = []
66
70
  params.each do |string|
67
71
  next unless string
68
72
 
69
- arr << string.split(' ')
73
+ arr << string.split
70
74
  end
71
75
  arr.join(' ')
72
76
  end
73
77
 
74
78
  def process_params(params)
75
- params.dup.each do |k, v|
79
+ params.dup.each_key do |k|
76
80
  case k
77
81
  when 'for'
78
82
  params['htmlFor'] = params.delete('for')
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module VirtualDOM
2
4
  class VirtualNode
3
5
  attr_reader :name, :params, :children
@@ -15,7 +17,7 @@ module VirtualDOM
15
17
  def to_s_params
16
18
  return unless @params.any?
17
19
 
18
- ' ' + @params.map { |k, v| "#{k}=\"#{v}\"" }.join(' ')
20
+ " #{@params.map { |k, v| "#{k}=\"#{v}\"" }.join(" ")}"
19
21
  end
20
22
 
21
23
  def to_s_children
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Browser
3
5
  module_function
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Component
3
5
  module ClassMethods
@@ -1,27 +1,30 @@
1
- odule Porous
2
- module Component
3
- module Render
4
- def render
5
- raise Error, "Implement #render in #{self.class} component"
6
- end
1
+ # frozen_string_literal: true
7
2
 
8
- def render_if_root
9
- return unless @virtual_dom && @root_node
10
- new_virtual_dom = render_virtual_dom
11
- diff = VirtualDOM.diff @virtual_dom, new_virtual_dom
12
- VirtualDOM.patch @root_node, diff
13
- @virtual_dom = new_virtual_dom
14
- end
3
+ module Porous
4
+ module Component
5
+ module Render
6
+ def render
7
+ raise Error, "Implement #render in #{self.class} component"
8
+ end
15
9
 
16
- def before_render; end;
10
+ def render_if_root
11
+ return unless @virtual_dom && @root_node
17
12
 
18
- def render_virtual_dom
19
- before_render
20
- @cache_component_counter = 0
21
- @__virtual_nodes__ = []
22
- render
23
- to_vnode
24
- end
25
- end
26
- end
13
+ new_virtual_dom = render_virtual_dom
14
+ diff = VirtualDOM.diff @virtual_dom, new_virtual_dom
15
+ VirtualDOM.patch @root_node, diff
16
+ @virtual_dom = new_virtual_dom
17
+ end
18
+
19
+ def before_render; end
20
+
21
+ def render_virtual_dom
22
+ before_render
23
+ @cache_component_counter = 0
24
+ @__virtual_nodes__ = []
25
+ render
26
+ to_vnode
27
+ end
28
+ end
29
+ end
27
30
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Component
3
5
  module Virtual
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Component
3
5
  include VirtualDOM::DOM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Porous
2
4
  module Injection
3
5
  def init; end
@@ -20,16 +22,14 @@ module Porous
20
22
 
21
23
  def init_injections
22
24
  @injections ||= {}
23
- self.class.injections.each do |name, clazz|
24
- if clazz.included_modules.include?(Porous::Injection)
25
- @injections[name] = clazz
26
- .new
27
- .with_root_component(@root_component)
28
- else
29
- raise Error, "Invalid #{clazz} class, should mixin Porous::Injection"
25
+ self.class.injections.each do |name, klass|
26
+ unless klass.included_modules.include?(Porous::Injection)
27
+ raise Error, "Invalid #{klass} class, should mixin Porous::Injection"
30
28
  end
29
+
30
+ @injections[name] = klass.new.with_root_component(@root_component)
31
31
  end
32
- @injections.each do |key, instance|
32
+ @injections.each_value do |instance|
33
33
  instance.inject
34
34
  instance.init
35
35
  end
data/opal/porous.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'opal'
2
4
  require 'native'
3
5
  require 'promise'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: porous
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Exa Stencil
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-15 00:00:00.000000000 Z
11
+ date: 2024-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rackup
14
+ name: listen
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.1'
19
+ version: '3.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.1'
26
+ version: '3.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: opal-browser
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,89 +53,33 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.6.1
55
55
  - !ruby/object:Gem::Dependency
56
- name: thor
56
+ name: rackup
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '1.3'
61
+ version: '2.1'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.3'
68
+ version: '2.1'
69
69
  - !ruby/object:Gem::Dependency
70
- name: listen
70
+ name: thor
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '3.0'
75
+ version: '1.3'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '3.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: '13.0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '13.0'
97
- - !ruby/object:Gem::Dependency
98
- name: rspec
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '3.2'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '3.2'
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '1.21'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '1.21'
125
- - !ruby/object:Gem::Dependency
126
- name: solargraph
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: 0.50.0
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: 0.50.0
82
+ version: '1.3'
139
83
  description: Highly opinionated web engine (not a framework!) that can be scripted
140
84
  with Ruby.
141
85
  email:
@@ -190,6 +134,7 @@ metadata:
190
134
  homepage_uri: https://github.com/exastencil/porous
191
135
  source_code_uri: https://github.com/exastencil/porous
192
136
  changelog_uri: https://github.com/exastencil/porous/blob/main/CHANGELOG.md
137
+ rubygems_mfa_required: 'true'
193
138
  post_install_message:
194
139
  rdoc_options: []
195
140
  require_paths: