lissio 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,5 @@
1
+ vendor
2
+ *.gem
3
+ .bundle
4
+ copycat
5
+ notes
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'opal', github: 'opal/opal'
5
+ gem 'opal-browser', github: 'opal/opal-browser'
6
+ gem 'parslet', github: 'kschiess/parslet'
7
+ gem 'rake'
@@ -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
@@ -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.
@@ -0,0 +1,5 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ require 'opal/spec/rake_task'
5
+ Opal::Spec::RakeTask.new(:default)
@@ -0,0 +1,5 @@
1
+ require 'opal'
2
+
3
+ require 'lissio/server'
4
+
5
+ Opal.append_path File.expand_path('../../opal', __FILE__)
@@ -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
@@ -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