snabberb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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>