snabberb 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: adebae58664968503236700933371f7d76003468056be676156f39c268edb88c
4
+ data.tar.gz: 41124f485907d7a84e537191ac8fad844f21beb009ddf7a1979a3d44e1b33522
5
+ SHA512:
6
+ metadata.gz: 5038c8f60b03ea4bf7e2d3f636007ae4f393ced975fef43aa75bcc0abd6e97e530320dea6787e952a97d7bea238057b55927fd191044461f20533b23c06a93cc
7
+ data.tar.gz: 0c4f20f341244f14e64c88828d194f4ae582394910e65a10f63da781d229e721f7fbbf49e8d3f23d0d5ec4df52fae474c27f35d1d9f994b2cb874007afff700f
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ .DS_STORE
11
+ *.swp
12
+ /Gemfile.lock
13
+
14
+ # rspec failure tracking
15
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,37 @@
1
+ Layout/IndentFirstArrayElement:
2
+ Enabled: false
3
+
4
+ Metrics/AbcSize:
5
+ Enabled: false
6
+
7
+ Metrics/BlockLength:
8
+ Enabled: False
9
+ Metrics/LineLength:
10
+ Max: 120
11
+
12
+ Metrics/MethodLength:
13
+ Enabled: false
14
+
15
+ Style/ClassVars:
16
+ Enabled: false
17
+
18
+ Style/CommandLiteral:
19
+ Enabled: false
20
+
21
+ Style/Documentation:
22
+ Enabled: false
23
+
24
+ Style/EmptyCaseCondition:
25
+ Enabled: false
26
+
27
+ Style/TrailingCommaInArguments:
28
+ Enabled: false
29
+
30
+ Style/TrailingCommaInArrayLiteral:
31
+ Enabled: false
32
+
33
+ Style/TrailingCommaInHashLiteral:
34
+ Enabled: false
35
+
36
+ AllCops:
37
+ TargetRubyVersion: 2.6
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.1
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Tobias Mao
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # Snabberb
2
+
3
+ Snabberb is a simple Ruby view framework built on [Opal](https://github.com/opal/opal) and [Snabbdom](https://github.com/snabbdom/snabbdom).
4
+
5
+ You can write reactive views in plain Ruby that compile to efficient Javascript.
6
+
7
+ ## Inline Example
8
+
9
+ ```ruby
10
+ require 'opal'
11
+ require 'snabberb'
12
+
13
+ class TextBox < Snabberb::Component
14
+ needs :text
15
+ needs :selected, default: false, store: true
16
+
17
+ def render
18
+ onclick = lambda do
19
+ store(:selected, !@selected)
20
+ end
21
+
22
+ style = {
23
+ cursor: 'pointer',
24
+ border: 'solid 1px rgba(0,0,0,0.2)',
25
+ }
26
+
27
+ style['background-color'] = 'lightblue' if @selected
28
+
29
+ h(:div, { style: style, on: { click: onclick } }, [
30
+ h(:div, @text)
31
+ ])
32
+ end
33
+ end
34
+
35
+
36
+ # Assuming you have a DOM element with ID=app
37
+ TextBox.attach('app', text: 'hello world')
38
+
39
+ # Or you can get the HTML string for isomorphic applications
40
+ TextBox.html(text: 'hello world')
41
+ ```
42
+
43
+ ## Examples
44
+ [Rack App](examples/rack)
45
+
46
+ ## Usage
47
+
48
+ ### Creating DOM Elements With h
49
+
50
+ Subclass Snabberb::Component and override #render to build divs using \#h.
51
+
52
+ Render should only return one root element.
53
+
54
+ \#h takes either a DOM symbol (:div, :span, :a, ...) or another Snabberb::Component class.
55
+
56
+ ```ruby
57
+ ...
58
+ class DomExample < Snabberb::Component
59
+ def render
60
+ h(:div)
61
+ end
62
+ end
63
+
64
+ class ComponentExample < Snabberb::Component
65
+ def render
66
+ h(OtherComponent)
67
+ end
68
+ end
69
+ ```
70
+
71
+ Like Snabbdom, \#h with DOM elements can take props which take the form of a dict.
72
+
73
+ ```ruby
74
+ ...
75
+ class PropsExample < Snabberb::Component
76
+ def render
77
+ h(:div, { style: { display: 'inline-block' }, class: { selected: true } })
78
+ end
79
+ end
80
+ ```
81
+
82
+ Components do not take props, instead they take [needs](#Needs) which are dependent arguments.
83
+
84
+ ```ruby
85
+ ...
86
+ class PassingNeedsExample < Snabberb::Component
87
+ def render
88
+ h(ChildComponent, need1: 1, need2: 2)
89
+ end
90
+ end
91
+ ```
92
+
93
+ \#h can also be nested with a child or multiple children.
94
+
95
+ ```ruby
96
+ ...
97
+ class NestedExample < Snabberb::Component
98
+ def render
99
+ h(:div, [
100
+ h(ChildComponent, need1: 1, need2: 2),
101
+ h(:div, { style: { width: '100px' } }, [
102
+ h(:div, 'hello'),
103
+ ])
104
+ ](
105
+ end
106
+ end
107
+ ```
108
+
109
+ ### Needs
110
+
111
+ Components can define needs which allow parent components to pass down arguments. They can also be stateful which allows changes to propogate easily throughout the application.
112
+
113
+ Needs are by default required. They can be set with default values. Needs are accesible with instance variables that are automatically set.
114
+
115
+ ```ruby
116
+ ...
117
+ class NeedsExample < Snabberb::Component
118
+ needs :name
119
+ needs :value, default: 0, store: true
120
+
121
+ def render
122
+ onclick = lambda do
123
+ store(:value, @value + 1)
124
+ end
125
+
126
+ h(:div, [
127
+ h(:div, @name),
128
+ h(:div, { on: { click: onclick} }, @value),
129
+ ])
130
+ end
131
+ end
132
+ ```
133
+
134
+ When simple state changes must be tracked, a need can define store: true. This will use the stored value of this key which is set on the root node.
135
+ The precedence of need values is stored > passed needs > default value.
136
+
137
+ 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
+
139
+ ## Installation
140
+
141
+ Add this line to your application's Gemfile:
142
+
143
+ ```ruby
144
+ gem 'snabberb'
145
+ ```
146
+
147
+ And then execute:
148
+
149
+ $ bundle
150
+
151
+ Or install it yourself as:
152
+
153
+ $ gem install snabberb
154
+
155
+ ## Development
156
+
157
+ ```
158
+ bundle install
159
+ bundle exec rake
160
+ ```
161
+ ## Contributing
162
+
163
+ Bug reports and pull requests are welcome on GitHub at https://github.com/tobymao/snabberb.
164
+
165
+ ## License
166
+
167
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: %i[spec rubocop]
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'c_lexer'
6
+ gem 'opal'
7
+ gem 'rack'
8
+ gem 'snabberb', path: '../..'
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: ../..
3
+ specs:
4
+ snabberb (0.1.0)
5
+ opal (~> 1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.0)
11
+ c_lexer (2.5.3.0.0)
12
+ ast (~> 2.4.0)
13
+ parser (= 2.5.3.0)
14
+ opal (1.0.0)
15
+ ast (>= 2.3.0)
16
+ parser (= 2.5.3.0)
17
+ parser (2.5.3.0)
18
+ ast (~> 2.4.0)
19
+ rack (2.0.7)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ c_lexer
26
+ opal
27
+ rack
28
+ snabberb!
29
+
30
+ BUNDLED WITH
31
+ 2.0.2
@@ -0,0 +1,13 @@
1
+ # Rack Example
2
+
3
+ This is a simple example featuring a selectable and addable list.
4
+
5
+
6
+ ## Install and Run
7
+
8
+ ```
9
+ bundle install
10
+ bundle exec rackup
11
+ ```
12
+
13
+ Navigate to http://localhost:9292.
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'opal'
4
+ require 'snabberb'
5
+
6
+ class Row < Snabberb::Component
7
+ needs :index
8
+ needs :value
9
+ needs :selected_id, default: nil, store: true
10
+
11
+ def selected?
12
+ @index == @selected_id
13
+ end
14
+
15
+ def render
16
+ onclick = lambda do
17
+ store(:selected_id, selected? ? nil : @index)
18
+ end
19
+
20
+ style = {
21
+ cursor: 'pointer',
22
+ border: 'solid 1px rgba(0,0,0,0.2)',
23
+ }
24
+
25
+ style['background-color'] = 'lightblue' if selected?
26
+
27
+ h(:div, { style: style, on: { click: onclick } }, [
28
+ h(:div, @value)
29
+ ])
30
+ end
31
+ end
32
+
33
+ class Form < Snabberb::Component
34
+ needs :values, store: true
35
+
36
+ def render
37
+ input = h(:input, props: { type: 'text', value: @values.last })
38
+
39
+ onclick = lambda do |event|
40
+ value = input.JS['elm'].JS['value']
41
+ event.JS.preventDefault
42
+ store(:values, @values + [value])
43
+ end
44
+
45
+ h(:form, { style: { width: '300px' } }, [
46
+ input,
47
+ h(:button, { on: { click: onclick } }, 'Add row'),
48
+ ])
49
+ end
50
+ end
51
+
52
+ class Application < Snabberb::Component
53
+ needs :values, store: true
54
+
55
+ def render
56
+ rows = @values.map.with_index do |value, index|
57
+ h(Row, index: index, value: value)
58
+ end
59
+
60
+ h(:div, { style: { width: '100px' } }, [
61
+ h(:div, 'List of Fruits'),
62
+ *rows,
63
+ h(Form),
64
+ ])
65
+ end
66
+ end
67
+
68
+ Application.attach('app', values: %w[apple banana cantaloupe])
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler'
4
+ Bundler.require
5
+
6
+ # Instructions: bundle in this directory
7
+ # then run `bundle exec rackup` to start the server
8
+ # and browse to http://localhost:9292
9
+
10
+ # the directory where the code is (add to opal load path )
11
+ Opal.append_path('app')
12
+
13
+ run(Opal::SimpleServer.new do |s|
14
+ # the name of the ruby file to load. To use more files they must be required from here (see app)
15
+ s.main = 'application'
16
+ # need to set the index explicitly for opal server to pick it up
17
+ s.index_path = 'index.html.erb'
18
+ end)
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Snabberb Demo</title>
6
+ </head>
7
+ <body>
8
+ <div id="app"></div>
9
+ <%= javascript_include_tag 'application' %>
10
+ </body>
11
+ </html>