porous 0.1.0 → 0.1.1

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: 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: