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.
@@ -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