snabberb 0.1.1 → 0.2.0

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: 7d6d783a17ba02a615ad7a82b4f6f120b2fe805b4c3f19d0364aae38fc98a24a
4
- data.tar.gz: 528c609d9ca398ae2288e951d98673f3d69cd3d866000fc24d665024948cd458
3
+ metadata.gz: 9905574c98d778f67508b52d3195f97d3d95b00b6d8a729a086f74c48e03b532
4
+ data.tar.gz: 770cb2d53f5aa816c0e156ba231ad5bacc26b77fc118ce8c2963930b56faaf25
5
5
  SHA512:
6
- metadata.gz: 52793e19ab8991b24aea629724cb60e6f56dfdaae33318ce1098e12f44be4ca23c6acb0caec5f82e0ac0a2be4f0047f3507e67a7793fe4887d271a24638a128d
7
- data.tar.gz: 4e8e093484a519198de36a86d22885076263a3de437c2b253c8e8f203edd5ae63d2186e57bf9b0b22e856bc9acc290ae3e16a82c018d368448013a13b61a4608
6
+ metadata.gz: 1590dacc07bd3dab3da4c7cc5b799744242f29d08e2bd87bff32f56aedfdb50c70225910f4dd8d0ed95372c5f6a45f7fe359db42c7221e78133273b35c8c4cb2
7
+ data.tar.gz: 3d13da1d38258a606df13c4bdccb8afc2a38d15860f42a900718b903492cfdbe7a84d0342187cdde9bb3239075463cd5651785122bf7f00bcf008c745e1fccd6
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /examples/roda/public
9
10
 
10
11
  .DS_STORE
11
12
  *.swp
data/.rubocop.yml CHANGED
@@ -1,4 +1,4 @@
1
- Layout/IndentFirstArrayElement:
1
+ Layout/FirstArrayElementIndentation:
2
2
  Enabled: false
3
3
 
4
4
  Metrics/AbcSize:
@@ -34,4 +34,4 @@ Style/TrailingCommaInHashLiteral:
34
34
  Enabled: false
35
35
 
36
36
  AllCops:
37
- TargetRubyVersion: 2.6
37
+ TargetRubyVersion: 2.3
data/README.md CHANGED
@@ -43,6 +43,8 @@ TextBox.html(text: 'hello world')
43
43
  ## Examples
44
44
  [Rack App](examples/rack)
45
45
 
46
+ [Roda App with HTML Prerendering](examples/roda)
47
+
46
48
  ## Usage
47
49
 
48
50
  ### Creating DOM Elements With h
@@ -136,6 +138,16 @@ The precedence of need values is stored > passed needs > default value.
136
138
 
137
139
  Needs can be set with #store which will trigger a view update. Snabberb uses Snabbdom to update the DOM, so only the differences in the DOM are changed.
138
140
 
141
+ ### Prerendering
142
+
143
+ You can prerender your HTML by calling
144
+
145
+ ```ruby
146
+ Snabberb.prerender_script('LayoutClass', 'ApplicationClass', 'application_id', javascript_include_tags: '', **needs)
147
+ ```
148
+
149
+ A detailed example can be found [in the Roda example](examples/roda).
150
+
139
151
  ## Installation
140
152
 
141
153
  Add this line to your application's Gemfile:
@@ -1,20 +1,20 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- snabberb (0.1.0)
4
+ snabberb (0.2.0)
5
5
  opal (~> 1.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  ast (2.4.0)
11
- c_lexer (2.5.3.0.0)
11
+ c_lexer (2.6.4.1.1)
12
12
  ast (~> 2.4.0)
13
- parser (= 2.5.3.0)
14
- opal (1.0.0)
13
+ parser (= 2.6.4.1)
14
+ opal (1.0.1)
15
15
  ast (>= 2.3.0)
16
- parser (= 2.5.3.0)
17
- parser (2.5.3.0)
16
+ parser (~> 2.6)
17
+ parser (2.6.4.1)
18
18
  ast (~> 2.4.0)
19
19
  rack (2.0.7)
20
20
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'c_lexer'
6
+ gem 'execjs'
7
+ gem 'mini_racer'
8
+ gem 'opal'
9
+ gem 'opal-sprockets'
10
+ gem 'roda'
11
+ gem 'snabberb', path: '../..'
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: ../..
3
+ specs:
4
+ snabberb (0.2.0)
5
+ opal (~> 1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.0)
11
+ c_lexer (2.6.4.1.1)
12
+ ast (~> 2.4.0)
13
+ parser (= 2.6.4.1)
14
+ concurrent-ruby (1.1.5)
15
+ execjs (2.7.0)
16
+ libv8 (7.3.492.27.1)
17
+ mini_racer (0.2.8)
18
+ libv8 (>= 6.9.411)
19
+ opal (1.0.1)
20
+ ast (>= 2.3.0)
21
+ parser (~> 2.6)
22
+ opal-sprockets (0.4.8.1.0.3.7)
23
+ opal (~> 1.0.0)
24
+ sprockets (~> 3.7)
25
+ tilt (>= 1.4)
26
+ parser (2.6.4.1)
27
+ ast (~> 2.4.0)
28
+ rack (2.0.7)
29
+ roda (3.26.0)
30
+ rack
31
+ sprockets (3.7.2)
32
+ concurrent-ruby (~> 1.0)
33
+ rack (> 1, < 3)
34
+ tilt (2.0.10)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ c_lexer
41
+ execjs
42
+ mini_racer
43
+ opal
44
+ opal-sprockets
45
+ roda
46
+ snabberb!
47
+
48
+ BUNDLED WITH
49
+ 2.0.2
@@ -0,0 +1,14 @@
1
+ # Roda Example
2
+
3
+ This is an example using Roda. It features prerendering HTML and SVG rendering.
4
+
5
+ ![SVG Hexes](roda_example.png)
6
+
7
+ ## Install and Run
8
+
9
+ ```
10
+ bundle install
11
+ bundle exec rackup
12
+ ```
13
+
14
+ Navigate to http://localhost:9292.
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ class Tile < Snabberb::Component
6
+ def render
7
+ h(:g, { attrs: { transform: 'rotate(60)' } }, [
8
+ h(:path, attrs: { d: 'm 0 87 L 0 -87', stroke: 'black', 'stroke-width' => 8 }),
9
+ h(:path, attrs: { d: 'm -4 86 L -4 -86', stroke: 'white', 'stroke-width' => 2 }),
10
+ h(:path, attrs: { d: 'm 4 86 L 4 -86', stroke: 'white', 'stroke-width' => 2 }),
11
+ ])
12
+ end
13
+ end
14
+
15
+ class Hex < Snabberb::Component
16
+ SIZE = 100
17
+ POINTS = '100,0 50,-87 -50,-87 -100,-0 -50,87 50,87'
18
+
19
+ needs :x
20
+ needs :y
21
+ needs :selected, default: Set.new, store: true
22
+
23
+ def translation
24
+ offset = self.class::SIZE
25
+ x = self.class::SIZE * Math.sqrt(3) / 2 * @x + offset
26
+ y = self.class::SIZE * 3 / 2 * @y + offset
27
+ "translate(#{x}, #{y})"
28
+ end
29
+
30
+ def transform
31
+ "#{translation} rotate(30)"
32
+ end
33
+
34
+ def render
35
+ coordinates = [@x, @y]
36
+ selected = @selected.include?(coordinates)
37
+ children = [h(:polygon, attrs: { points: self.class::POINTS })]
38
+ children << h(Tile) if selected
39
+
40
+ onclick = lambda do
41
+ if selected
42
+ store(:selected, @selected - [coordinates])
43
+ else
44
+ store(:selected, @selected | [coordinates])
45
+ end
46
+ end
47
+
48
+ props = {
49
+ attrs: {
50
+ transform: transform,
51
+ fill: selected ? 'yellow' : 'white',
52
+ stroke: 'black',
53
+ },
54
+ style: { cursor: 'pointer' },
55
+ on: { click: onclick }
56
+ }
57
+
58
+ h(:g, props, children)
59
+ end
60
+ end
61
+
62
+ class Map < Snabberb::Component
63
+ needs :size_x
64
+ needs :size_y
65
+
66
+ def render
67
+ hexes = @size_x.times.flat_map do |x|
68
+ @size_y.times.map do |y|
69
+ h(Hex, x: y.even? ? x + 1 : x, y: x.even? ? y + 1 : y)
70
+ end
71
+ end
72
+
73
+ container_style = {
74
+ width: '100%',
75
+ height: '100%',
76
+ overflow: 'auto',
77
+ }
78
+
79
+ svg_style = {
80
+ width: "#{@size_x * 50}px",
81
+ height: "#{@size_y * 80}px",
82
+ }
83
+
84
+ h(:div, { props: { id: 'map_id' }, style: container_style }, [
85
+ h(:svg, { style: svg_style }, [
86
+ h(:g, { attrs: { transform: 'scale(0.5)' } }, hexes)
87
+ ])
88
+ ])
89
+ end
90
+ end
91
+
92
+ class Index < Snabberb::Layout
93
+ def render
94
+ h(:html, [
95
+ h(:head, [
96
+ h(:meta, props: { charset: 'utf-8' }),
97
+ h(:title, 'Roda Demo'),
98
+ ]),
99
+ h(:body, [
100
+ @application,
101
+ h(:div, props: { innerHTML: @javascript_include_tags }),
102
+ h(:script, props: { innerHTML: @attach_func }),
103
+ ]),
104
+ ])
105
+ end
106
+ end
@@ -0,0 +1,2 @@
1
+ if (typeof setTimeout === 'undefined') { function setTimeout(func) { func() } }
2
+ if (typeof OpalLoaded === 'undefined') { OpalLoaded = [] }
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'opal'
4
+ require 'polyfill'
5
+ require 'snabberb'
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'execjs'
4
+ require 'json'
5
+ require 'opal'
6
+ require 'opal/sprockets'
7
+ require 'roda'
8
+ require 'sprockets'
9
+ require 'snabberb'
10
+
11
+ LIB_NAME = 'lib.js'
12
+ LIB_PATH = "./public/#{LIB_NAME}"
13
+ Opal.append_path('app')
14
+ File.write(LIB_PATH, Opal::Builder.build('requires')) unless File.file?(LIB_PATH)
15
+
16
+ class App < Roda
17
+ plugin :public
18
+
19
+ context = ExecJS.compile(File.read(LIB_PATH) + Opal::Builder.build('application').to_s)
20
+
21
+ environment = Sprockets::Environment.new
22
+ Opal.paths.each { |p| environment.append_path(p) }
23
+
24
+ javascript_include_tags = "<script src=#{LIB_NAME}></script>" + Opal::Sprockets.javascript_include_tag(
25
+ 'application',
26
+ sprockets: environment,
27
+ prefix: '/assets',
28
+ debug: true,
29
+ )
30
+
31
+ route do |r|
32
+ r.public
33
+
34
+ r.on 'assets' do
35
+ r.run environment
36
+ end
37
+
38
+ r.root do
39
+ context.eval(
40
+ Snabberb.prerender_script(
41
+ 'Index',
42
+ 'Map',
43
+ 'map_id',
44
+ javascript_include_tags: javascript_include_tags,
45
+ size_x: 30,
46
+ size_y: 30,
47
+ )
48
+ )
49
+ end
50
+ end
51
+ end
52
+
53
+ run App.freeze.app
Binary file
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Snabberb
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/snabberb.rb CHANGED
@@ -1,6 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
3
4
  require 'opal'
4
5
  require 'snabberb/version'
5
6
 
6
- Opal.append_path File.expand_path('../opal', __dir__)
7
+ Opal.append_path(File.expand_path('../opal', __dir__))
8
+
9
+ module Snabberb
10
+ def self.prerender_script(layout, application, application_id, javascript_include_tags: '', **needs)
11
+ needs = JSON.generate(needs)
12
+
13
+ <<~JS
14
+ Opal.$$.#{layout}.$html(Opal.hash({
15
+ application: Opal.$$.#{application}.$new(null, Opal.hash(#{needs})).$render(),
16
+ javascript_include_tags: '#{javascript_include_tags.gsub("\n", '')}',
17
+ attach_func: 'Opal.$$.#{application}.$attach("#{application_id}", Opal.hash(#{needs}))'
18
+ }))
19
+ JS
20
+ end
21
+ end
@@ -16,12 +16,11 @@ module Snabberb
16
16
  # :default - Sets the default value, if not passed the need is considered required.
17
17
  # :store - Whether or not to store the need as state. The default is false.
18
18
  def self.needs(key, **opts)
19
- @class_needs ||= {}
20
- @class_needs[key] = opts
19
+ class_needs[key] = opts
21
20
  end
22
21
 
23
22
  def self.class_needs
24
- @class_needs || {}
23
+ @class_needs ||= superclass.respond_to?(:class_needs) ? superclass.class_needs.clone : {}
25
24
  end
26
25
 
27
26
  # Attach the root component to a dom element by container id.
@@ -145,4 +144,25 @@ module Snabberb
145
144
  end
146
145
  end
147
146
  end
147
+
148
+ # Sublcass this to prerender applications.
149
+ class Layout < Snabberb::Component
150
+ needs :application # the rendered application
151
+ needs :attach_func # function to reattach the application after dom load
152
+ needs :javascript_include_tags # all necessary javascript tags
153
+
154
+ # Example render function.
155
+ # def render
156
+ # h(:html, [
157
+ # h(:head, [
158
+ # h(:meta, { props: { charset: 'utf-8'} }),
159
+ # ]),
160
+ # h(:body, [
161
+ # @application,
162
+ # h(:div, { props: { innerHTML: @javascript_include_tags } }),
163
+ # h(:script, { props: { innerHTML: @attach_func} }),
164
+ # ]),
165
+ # ])
166
+ # end
167
+ end
148
168
  end
data/snabberb.gemspec CHANGED
@@ -25,13 +25,14 @@ Gem::Specification.new do |spec|
25
25
  spec.bindir = 'exe'
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = %w[lib opal]
28
+ spec.required_ruby_version = '>= 2.3'
28
29
 
29
30
  spec.add_dependency 'opal', '~> 1.0'
30
31
 
31
- spec.add_development_dependency 'bundler', '~> 2.0'
32
+ spec.add_development_dependency 'bundler'
32
33
  spec.add_development_dependency 'c_lexer'
33
34
  spec.add_development_dependency 'execjs'
34
- spec.add_development_dependency 'rake', '~> 12.0'
35
- spec.add_development_dependency 'rspec', '~> 3.0'
36
- spec.add_development_dependency 'rubocop', '~> 0.7'
35
+ spec.add_development_dependency 'rake'
36
+ spec.add_development_dependency 'rspec'
37
+ spec.add_development_dependency 'rubocop'
37
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snabberb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toby Mao
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-08 00:00:00.000000000 Z
11
+ date: 2019-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opal
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '2.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '2.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: c_lexer
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -70,44 +70,44 @@ dependencies:
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '12.0'
75
+ version: '0'
76
76
  type: :development
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: '12.0'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '3.0'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '3.0'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - "~>"
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '0.7'
103
+ version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - "~>"
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '0.7'
110
+ version: '0'
111
111
  description: 'Snabberb is a minimalistic Opal view framework based on Snabbdom. You
112
112
  can write efficient reactive Javascript in pure Ruby. Snabberb also provides a simple
113
113
  way to track state.
@@ -133,6 +133,14 @@ files:
133
133
  - examples/rack/app/application.rb
134
134
  - examples/rack/config.ru
135
135
  - examples/rack/index.html.erb
136
+ - examples/roda/Gemfile
137
+ - examples/roda/Gemfile.lock
138
+ - examples/roda/README.md
139
+ - examples/roda/app/application.rb
140
+ - examples/roda/app/polyfill.js
141
+ - examples/roda/app/requires.rb
142
+ - examples/roda/config.ru
143
+ - examples/roda/roda_example.png
136
144
  - lib/snabberb.rb
137
145
  - lib/snabberb/version.rb
138
146
  - opal/snabberb.rb
@@ -159,7 +167,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
167
  requirements:
160
168
  - - ">="
161
169
  - !ruby/object:Gem::Version
162
- version: '0'
170
+ version: '2.3'
163
171
  required_rubygems_version: !ruby/object:Gem::Requirement
164
172
  requirements:
165
173
  - - ">="