lissio 0.1.0.beta1
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 +7 -0
- data/.gitignore +5 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +53 -0
- data/README.md +184 -0
- data/Rakefile +5 -0
- data/lib/lissio.rb +5 -0
- data/lib/lissio/server.rb +148 -0
- data/lissio.gemspec +27 -0
- data/opal/lissio.rb +26 -0
- data/opal/lissio/adapter.rb +45 -0
- data/opal/lissio/adapter/rest.rb +268 -0
- data/opal/lissio/adapter/storage.rb +167 -0
- data/opal/lissio/application.rb +66 -0
- data/opal/lissio/collection.rb +70 -0
- data/opal/lissio/component.rb +177 -0
- data/opal/lissio/component/alert.rb +110 -0
- data/opal/lissio/component/container.rb +56 -0
- data/opal/lissio/component/markdown.rb +332 -0
- data/opal/lissio/component/tooltip.rb +373 -0
- data/opal/lissio/model.rb +204 -0
- data/opal/lissio/router.rb +164 -0
- data/opal/lissio/version.rb +3 -0
- data/spec/route_spec.rb +65 -0
- data/spec/router_spec.rb +109 -0
- data/spec/spec_helper.rb +33 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0f0f172ff0e936f469a65ec836bf667540493078
|
4
|
+
data.tar.gz: 19eeeaa38dec2bc28f36bae0e477aace77ebc22a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a55d054ac98ec0d76ac2fb7bb76d4b2828bdead360139a877f053f375309cd05fe0253634ecaafe240c18d7c2582268303609dc660c47b47f929c5fc2c37da40
|
7
|
+
data.tar.gz: 32ef95d19670fcd5e291ada0ebc8d222106bc34b3f59ae1f24ee370c81338ed0ffbc03df830d956546bac94b538c191cb42f5235e6b60cf31e19bd1f3cb3ee3e
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/opal/opal-browser.git
|
3
|
+
revision: 49e60b355580e6acf8ed7a62325b58c4a75bccfd
|
4
|
+
specs:
|
5
|
+
opal-browser (0.1.0)
|
6
|
+
opal (>= 0.3.44)
|
7
|
+
|
8
|
+
GIT
|
9
|
+
remote: git://github.com/opal/opal.git
|
10
|
+
revision: 9760cc785d29fc6aab66021213dd2be09bfb3cbc
|
11
|
+
specs:
|
12
|
+
opal (0.4.3)
|
13
|
+
source_map
|
14
|
+
|
15
|
+
PATH
|
16
|
+
remote: .
|
17
|
+
specs:
|
18
|
+
lissio (0.1.0)
|
19
|
+
opal (>= 0.4.1)
|
20
|
+
opal-browser
|
21
|
+
|
22
|
+
GEM
|
23
|
+
remote: https://rubygems.org/
|
24
|
+
specs:
|
25
|
+
hike (1.2.3)
|
26
|
+
json (1.8.0)
|
27
|
+
multi_json (1.7.7)
|
28
|
+
opal-spec (0.2.17)
|
29
|
+
opal (~> 0.4.1)
|
30
|
+
opal-sprockets (~> 0.1.0)
|
31
|
+
opal-sprockets (0.1.1)
|
32
|
+
opal (~> 0.4.0)
|
33
|
+
sprockets
|
34
|
+
rack (1.5.2)
|
35
|
+
rake (10.1.0)
|
36
|
+
source_map (3.0.1)
|
37
|
+
json
|
38
|
+
sprockets (2.10.0)
|
39
|
+
hike (~> 1.2)
|
40
|
+
multi_json (~> 1.0)
|
41
|
+
rack (~> 1.0)
|
42
|
+
tilt (~> 1.1, != 1.3.0)
|
43
|
+
tilt (1.4.1)
|
44
|
+
|
45
|
+
PLATFORMS
|
46
|
+
ruby
|
47
|
+
|
48
|
+
DEPENDENCIES
|
49
|
+
lissio!
|
50
|
+
opal!
|
51
|
+
opal-browser!
|
52
|
+
opal-spec
|
53
|
+
rake
|
data/README.md
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
lissio - e vai col lissio
|
2
|
+
=========================
|
3
|
+
**lissio** is a VCL (Vai Col Lissio) framework for [Opal](http://opalrb.org) to
|
4
|
+
implement frontends completely on the client side.
|
5
|
+
|
6
|
+
[Here](http://www.youtube.com/watch?v=7JU5ssyKczw) you can find the best
|
7
|
+
musical background while developing **lissio** applications.
|
8
|
+
|
9
|
+
Application
|
10
|
+
-----------
|
11
|
+
Every **lissio** frontend begins with an `Application` singleton.
|
12
|
+
|
13
|
+
A `Lissio::Application` singleton is a `Lissio::Component` that takes ownership
|
14
|
+
of the `body` element and renders itself on it, since it's just a component you
|
15
|
+
can do anything you can do with any other component.
|
16
|
+
|
17
|
+
It also internally creates a router, so you can define the routes and what they
|
18
|
+
do directly in the `#initialize` method.
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
class MyApplication < Lissio::Application
|
22
|
+
def initialize
|
23
|
+
super
|
24
|
+
|
25
|
+
route '/' do
|
26
|
+
alert "This is an awesome index, ain't it?"
|
27
|
+
end
|
28
|
+
|
29
|
+
route '/about' do
|
30
|
+
alert "I don't know you, you don't know me"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Component
|
37
|
+
---------
|
38
|
+
Components are the heart of any lissio application, in the MVC pattern a lissio
|
39
|
+
component would be a mix of a view and a controller.
|
40
|
+
|
41
|
+
Every component has the ability to define the HTML, the CSS and the behaviour
|
42
|
+
in pure Ruby using various DSLs.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class MyComponent < Lissio::Component
|
46
|
+
tag class: 'my-component'
|
47
|
+
|
48
|
+
on :click, '.title' do
|
49
|
+
alert 'You clicked on the title'
|
50
|
+
end
|
51
|
+
|
52
|
+
on :hover, '.subtitle' do
|
53
|
+
alert 'You hovered over the subtitle'
|
54
|
+
end
|
55
|
+
|
56
|
+
html do
|
57
|
+
div.title 'hue'
|
58
|
+
div.subtitle 'huehuehuehue'
|
59
|
+
end
|
60
|
+
|
61
|
+
css do
|
62
|
+
rule '.my-component' do
|
63
|
+
rule '.title' do
|
64
|
+
font size: 32.px
|
65
|
+
end
|
66
|
+
|
67
|
+
rule '.subtitle' do
|
68
|
+
font size: 18.px,
|
69
|
+
style: :italic
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
Every component has a `#render` method, once it's called it will create an
|
77
|
+
element based on the `#tag` definition or render itself in the defined
|
78
|
+
`#element`.
|
79
|
+
|
80
|
+
On rendering the `#html` DSL block will produce the DOM directly, there won't
|
81
|
+
be any generate-parse passes, and the `#css` block will generate the CSS style
|
82
|
+
and put it in the `<head>`
|
83
|
+
|
84
|
+
Model
|
85
|
+
-----
|
86
|
+
Models are the classic models, they have properties and can be populated using
|
87
|
+
adapters.
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
class Message < Lissio::Model
|
91
|
+
property :id, as: Integer, primary: true
|
92
|
+
property :at, as: Time, default: -> { Time.now }
|
93
|
+
property :content, as: String
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
You can then instantiate the model `Message.new(id: 2, content: "huehue")`.
|
98
|
+
|
99
|
+
Collection
|
100
|
+
----------
|
101
|
+
Collections are, well, collections of models, they're separate entities since
|
102
|
+
they can have different adapters and have different methods of fetching or
|
103
|
+
working on the models they contain.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
class Messages < Lissio::Collection
|
107
|
+
model Message
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
Adapter
|
112
|
+
-------
|
113
|
+
Without adapters models and collections would be pretty much useless since you
|
114
|
+
wouldn't be able to persist them.
|
115
|
+
|
116
|
+
When you define a model you can set an adapter calling the `#adapter` method.
|
117
|
+
|
118
|
+
**lissio** comes with two default adapters, REST and localStorage, they take
|
119
|
+
various options to define endpoints and other behaviour.
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
class Message < Lissio::Model
|
123
|
+
adapter Lissio::Adapter::REST, endpoint: '/message'
|
124
|
+
|
125
|
+
property :id, as: Integer, primary: true
|
126
|
+
property :at, as: Time, default: -> { Time.now }
|
127
|
+
property :content, as: String
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
Now you'll be able to fetch a model like this.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
Message.fetch(1) {|msg|
|
135
|
+
if Message === msg
|
136
|
+
alert msg.content
|
137
|
+
else
|
138
|
+
alert msg.inspect
|
139
|
+
end
|
140
|
+
}
|
141
|
+
```
|
142
|
+
|
143
|
+
When you do operations using adapters you'll always have to provide a block
|
144
|
+
that will be called, since all operations are asynchronous.
|
145
|
+
|
146
|
+
The class check is done because the block will be either passed the model or an
|
147
|
+
error.
|
148
|
+
|
149
|
+
Server
|
150
|
+
------
|
151
|
+
**lissio** comes with a server to run and provide the built application, you're
|
152
|
+
not forced to use it, but it provides seamless access to the HTML5 history.
|
153
|
+
|
154
|
+
This means it always gives you the index when accessing any URL that isn't a
|
155
|
+
static file.
|
156
|
+
|
157
|
+
In the future it will do prerendering using phantomjs to make **lissio**
|
158
|
+
applications indexable and crawlable by search engines, so you might want to
|
159
|
+
stick with it.
|
160
|
+
|
161
|
+
Following an example on how to run the server.
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
require 'bundler'
|
165
|
+
Bundler.require
|
166
|
+
|
167
|
+
run Lissio::Server.new {|s|
|
168
|
+
s.append_path 'app'
|
169
|
+
s.append_path 'css'
|
170
|
+
s.append_path 'js'
|
171
|
+
|
172
|
+
s.index = 'index.html.erb'
|
173
|
+
s.debug = true
|
174
|
+
}
|
175
|
+
```
|
176
|
+
|
177
|
+
The application usually goes in `app/`.
|
178
|
+
|
179
|
+
External CSS should go in `css/`, usually you don't need to write CSS at all,
|
180
|
+
you should just use the `#css` method in the component.
|
181
|
+
|
182
|
+
External JavaScript should go in `js/`, typically compatibility files like
|
183
|
+
`json2` and `sizzle` go there, or other libraries you are using that aren't
|
184
|
+
Opal libraries.
|
data/Rakefile
ADDED
data/lib/lissio.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'rack/file'
|
2
|
+
require 'rack/urlmap'
|
3
|
+
require 'rack/builder'
|
4
|
+
require 'rack/directory'
|
5
|
+
require 'rack/showexceptions'
|
6
|
+
require 'opal/source_map'
|
7
|
+
require 'opal/sprockets/environment'
|
8
|
+
|
9
|
+
require 'forwardable'
|
10
|
+
|
11
|
+
module Lissio
|
12
|
+
|
13
|
+
class Server
|
14
|
+
class SourceMap
|
15
|
+
attr_accessor :prefix
|
16
|
+
|
17
|
+
def initialize(sprockets)
|
18
|
+
@sprockets = sprockets
|
19
|
+
@prefix = '/__opal_source_maps__'
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
if asset = @sprockets[env['PATH_INFO'].gsub(/^\/|\.js\.map$/, '')]
|
24
|
+
[200, { "Content-Type" => "text/json" }, [$OPAL_SOURCE_MAPS[asset.pathname].to_s]]
|
25
|
+
else
|
26
|
+
[404, {}, []]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Prerenderer
|
32
|
+
def initialize(app, server)
|
33
|
+
@app = app
|
34
|
+
@server = server
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(env)
|
38
|
+
@app.call(env)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Index
|
43
|
+
def initialize(server)
|
44
|
+
@server = server
|
45
|
+
@path = server.index
|
46
|
+
end
|
47
|
+
|
48
|
+
def call(env)
|
49
|
+
if env['PATH_INFO'] =~ /\.[^.]+$/
|
50
|
+
[404, {"Content-Type" => "text/plain"}, []]
|
51
|
+
else
|
52
|
+
[200, { 'Content-Type' => 'text/html' }, [html]]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def html
|
57
|
+
source = if @path
|
58
|
+
unless File.exist?(@path)
|
59
|
+
raise "index does not exist: #{@path}"
|
60
|
+
end
|
61
|
+
|
62
|
+
File.read @path
|
63
|
+
elsif File.exist? 'index.html'
|
64
|
+
File.read 'index.html'
|
65
|
+
elsif File.exist? 'index.html.erb'
|
66
|
+
File.read 'index.html.erb'
|
67
|
+
else
|
68
|
+
<<-HTML
|
69
|
+
<!DOCTYPE html>
|
70
|
+
<html>
|
71
|
+
<head>
|
72
|
+
<%= lissio %>
|
73
|
+
</head>
|
74
|
+
<body>
|
75
|
+
</body>
|
76
|
+
</html>
|
77
|
+
HTML
|
78
|
+
end
|
79
|
+
|
80
|
+
::ERB.new(source).result binding
|
81
|
+
end
|
82
|
+
|
83
|
+
def lissio(source = @server.main)
|
84
|
+
if @server.debug
|
85
|
+
if (assets = @server.sprockets[source].to_a).empty?
|
86
|
+
raise "Cannot find asset: #{source}"
|
87
|
+
end
|
88
|
+
|
89
|
+
assets.map {|a|
|
90
|
+
%Q{<script src="/assets/#{a.logical_path}?body=1"></script>}
|
91
|
+
}.join ?\n
|
92
|
+
else
|
93
|
+
"<script src=\"/assets/#{source}.js\"></script>"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
extend Forwardable
|
99
|
+
|
100
|
+
attr_accessor :debug, :index, :main, :static, :source_maps, :sprockets
|
101
|
+
def_delegators :@sprockets, :append_path, :use_gem
|
102
|
+
|
103
|
+
def initialize(options = {}, &block)
|
104
|
+
@sprockets = Opal::Environment.new
|
105
|
+
|
106
|
+
block.call(self) if block
|
107
|
+
end
|
108
|
+
|
109
|
+
def source_maps?
|
110
|
+
@source_maps
|
111
|
+
end
|
112
|
+
|
113
|
+
def extend(&block)
|
114
|
+
@extend = block
|
115
|
+
end
|
116
|
+
|
117
|
+
def app
|
118
|
+
this = self
|
119
|
+
block = @extend
|
120
|
+
|
121
|
+
@app ||= Rack::Builder.app do
|
122
|
+
use Rack::ShowExceptions
|
123
|
+
|
124
|
+
map '/assets' do
|
125
|
+
run this.sprockets
|
126
|
+
end
|
127
|
+
|
128
|
+
if this.source_maps?
|
129
|
+
map this.source_maps.prefix do
|
130
|
+
run this.source_maps
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
use Prerenderer, this
|
135
|
+
use Rack::Static, urls: this.static if this.static
|
136
|
+
|
137
|
+
instance_exec(&block) if block
|
138
|
+
|
139
|
+
run Index.new(this)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def call(env)
|
144
|
+
app.call(env)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
data/lissio.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH << File.expand_path('../opal', __FILE__)
|
3
|
+
require 'lissio/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'lissio'
|
7
|
+
s.version = Lissio::VERSION
|
8
|
+
s.author = 'meh.'
|
9
|
+
s.email = 'meh@schizofreni.co'
|
10
|
+
s.homepage = 'https://github.com/meh/lissio'
|
11
|
+
s.summary = '.'
|
12
|
+
s.description = '..'
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.add_dependency 'opal', '>= 0.5.5'
|
20
|
+
s.add_dependency 'opal-browser'
|
21
|
+
s.add_dependency 'rack'
|
22
|
+
|
23
|
+
s.add_development_dependency 'opal-spec'
|
24
|
+
s.add_development_dependency 'rake'
|
25
|
+
|
26
|
+
s.add_dependency 'thor'
|
27
|
+
end
|