vitrine 0.0.7 → 0.0.9

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
+ SHA1:
3
+ metadata.gz: ad569a8f77f0b68b74690887547a4b0b59e2de6c
4
+ data.tar.gz: eedc4cd325749f108a518be915db23b78974b39d
5
+ SHA512:
6
+ metadata.gz: 7b6937c1067c446acf3f187df58004da35babcc8204450812e56d2ff0baac3c382649b55c0b743690ee6af1d4d798eae3e594225cf498c7b1b53b7d463a0df97
7
+ data.tar.gz: 9cfb7408119fcf4b81d4b42d71e55ec97724ccefbeeef350751f59b9c6d0d2786cceaca70e9c71216f023ebc6470022376bac981c44e1c12410995f96490e585
data/Gemfile CHANGED
@@ -1,7 +1,4 @@
1
1
  source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
5
2
 
6
3
  gem 'sinatra', '~> 1.4', require: 'sinatra/base'
7
4
  gem 'coffee-script', '~> 2.2'
data/README.rdoc CHANGED
@@ -1,13 +1,17 @@
1
1
  = vitrine
2
2
 
3
3
  Is a very small, simple web server one-liner for modern web-apps, a bit in the style of
4
- lineman, serve and such.
4
+ lineman, serve and such. Will display your precious stuff on port 4000.
5
5
 
6
6
  == Core idea of Vitrine
7
7
 
8
8
  You want a server that will automatically wrap your CoffeeScript and SASS assets, and allow
9
9
  some rudimentary templating. This is practically enough for putting together MVP prototypes,
10
- especially as far as single-page apps go.
10
+ especially as far as single-page apps go. You want this server to not coerce you into a specific
11
+ SCSS framework, you don't want to scaffold anything, you don't want to have any configs defined and
12
+ you hate running wizards.
13
+
14
+ If most of the above is true, Vitrine is just what you need.
11
15
 
12
16
  == How it works.
13
17
 
@@ -15,22 +19,40 @@ Vitrine assumes that there are two directories under the current tree:
15
19
  * "public" - for the JS, for CSS and SCSS and in general all the static files server straight out
16
20
  * "views" - for the templates
17
21
 
18
- == Automatic compilation of assets
22
+ == Automatic compilation of SCSS
23
+
24
+ Any .scss file you shove into the "public" directory can be referenced as ".css" from your HTML code.
25
+ Vitrine will automatically compile it via SASS.
26
+
27
+ == Automatic compilation of CoffeeScript and source maps
28
+
29
+ Same thing applies to CoffeeScript - put .coffee files in "public", and reference them as .js files.
30
+ Vitrine will generate you source maps on the fly for pleasant browser debugging.
19
31
 
20
- From there on, any .scss file you shove into the "public" directory can be referenced as ".css" -
21
- Vitrine will automatically compile it via SASS. Same thing applies to CoffeeScript - put .coffee
22
- files in "public", and reference them as .js files.
32
+ == Fallback to precompiled files
23
33
 
24
- Both of the above work as passthrough URLs - if you have real JS in there the files will be served
25
- as static assets. Also, once you compile the site for deployment your links won't go stale.
34
+ Both SCSS and JS links will fall through to the static versions if you cache them on the server or as a result of
35
+ asset compilation.
26
36
 
27
- Vitrine will try to show you sensible errors if your SCSS or CoffeeScript fail to compile.
37
+ == Sensible error messages when automatic compilation fails
28
38
 
29
- == Automatic template pickup
39
+ Vitrine will try to show you sensible errors if your SCSS or CoffeeScript fail to compile due to syntax errors and
40
+ the like.
30
41
 
31
- If you have "views" available, Vitrine will try to pick up any usable file for any URL without extensions.
42
+ == Do not recompile on every request
43
+
44
+ Succesfully compiled assets will be stored in your +/tmp+ to save time on next reload, and the
45
+ cache will be automatically flushed when the files are requested from the browser, but only if the modification
46
+ dates of the source files are different than before.
47
+
48
+ == Automatic Ruby template pickup
49
+
50
+ If you have the "views" directory available, Vitrine will try to pick up any usable file for any URL without extensions.
32
51
  From there on, it's going to try to render it with the automatically picked template engine using the
33
- standard Sinatra facilities.
52
+ standard Sinatra facilities. You can use HAML, LESS, Slim, ERB, Builder or anything else you like.
53
+
54
+ If you are writing an SPA, you can make a file called "catch_all.erb" which is going to be the fall-through template
55
+ for all missing URLs without extension.
34
56
 
35
57
  == Automatic reload via Guard
36
58
 
@@ -40,7 +62,9 @@ rack-livereload, so you won't need browser extensions at all.
40
62
  == Packaging and baking
41
63
 
42
64
  At this point the best way to bake a Vitrine site is to crawl it externally, but we are going to implement
43
- baking at some point.
65
+ baking at some point. The idea is that you will end up upgrading the site to either a Node app or a Ruby app
66
+ with it's own +config.ru+ - if after that point you still wish to use Vitrine, you can use it like a Rack
67
+ middleware.
44
68
 
45
69
  == Contributing to vitrine
46
70
 
@@ -0,0 +1,35 @@
1
+ module Vitrine
2
+ # Stolen from Rails
3
+ def self.atomic_write(file_name, temp_dir = Dir.tmpdir)
4
+ require 'tempfile' unless defined?(Tempfile)
5
+ require 'fileutils' unless defined?(FileUtils)
6
+
7
+ temp_file = Tempfile.new(File.basename(file_name), temp_dir)
8
+ temp_file.binmode
9
+ yield temp_file
10
+ temp_file.close
11
+
12
+ begin
13
+ # Get original file permissions
14
+ old_stat = File.stat(file_name)
15
+ rescue Errno::ENOENT
16
+ # No old permissions, write a temp file to determine the defaults
17
+ check_name = File.join(File.dirname(file_name), ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}")
18
+ open(check_name, "w") { }
19
+ old_stat = File.stat(check_name)
20
+ File.unlink(check_name)
21
+ end
22
+
23
+ # Overwrite original file with temp file
24
+ FileUtils.mv(temp_file.path, file_name)
25
+
26
+ # Set correct permissions on new file
27
+ begin
28
+ File.chown(old_stat.uid, old_stat.gid, file_name)
29
+ # This operation will affect filesystem ACL's
30
+ File.chmod(old_stat.mode, file_name)
31
+ rescue Errno::EPERM
32
+ # Changing file ownership failed, moving on.
33
+ end
34
+ end
35
+ end
data/lib/sourcemaps.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'pathname'
2
+ require 'json'
3
+
4
+ module Vitrine
5
+ def self.build_coffeescript_source_map_body(full_coffeescript_file_path, public_dir_path)
6
+
7
+ script = File.read(full_coffeescript_file_path)
8
+
9
+ # We need to feed paths ON THE SERVER so that the browser can connect the coffee file, the map and the JS file
10
+ # - specify coffee source file explicitly (see http://coffeescript.org/documentation/docs/sourcemap.html#section-8)
11
+ # The paths need to be slash-prepended (server-absolute)
12
+ relative_path = '/' + Pathname.new(full_coffeescript_file_path).relative_path_from(Pathname.new(public_dir_path)).to_s
13
+ relative_js_path = '/' + relative_path.gsub(/\.coffee$/, '.js')
14
+
15
+ options = {sourceMap: true}
16
+
17
+ # coffee requires filename option to work with source maps (see http://coffeescript.org/documentation/docs/coffee-script.html#section-4)
18
+ options[:filename] = relative_js_path
19
+ options[:sourceFiles] = [relative_path]
20
+
21
+ CoffeeScript.compile(script, options)["v3SourceMap"]
22
+ end
23
+ end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Vitrine
2
- VERSION = '0.0.7'
2
+ VERSION = '0.0.9'
3
3
  end
data/lib/vitrine.rb CHANGED
@@ -1,12 +1,16 @@
1
1
  require 'sinatra/base'
2
2
  require 'coffee-script'
3
+ #require 'coffee-script-source'
3
4
  require 'sass'
4
5
  require 'pathname'
5
6
 
6
7
  require_relative 'version'
8
+ require_relative 'atomic_write'
9
+ require_relative 'sourcemaps'
7
10
 
8
11
  module Vitrine
9
12
  DEFAULTS = { root: Dir.getwd, port: 4000, host: '127.0.0.1' }
13
+ SEED = rand
10
14
 
11
15
  def self.check_dirs_present!
12
16
  views = DEFAULTS[:root] + '/views'
@@ -133,18 +137,15 @@ class Vitrine::App < Sinatra::Base
133
137
  template_engine = File.extname(template_path).gsub(/^\./, '')
134
138
  render(template_engine, File.read(template_path), :layout => get_layout, :locals => locals)
135
139
  end
136
-
137
- def get_layout
138
- layouts = Dir.glob(File.join(settings.views, 'layout.*'))
139
- layouts.any? ? :layout : false
140
- end
140
+
141
141
 
142
142
  # Try to find SCSS replacement for missing CSS
143
143
  get /(.+)\.css/ do | basename |
144
144
  begin
145
145
  content_type 'text/css', :charset => 'utf-8'
146
+ # TODO: has no handling for .sass
146
147
  scss_source_path = File.join(settings.root, 'public', "#{basename}.scss")
147
- Sass.compile_file(scss_source_path)
148
+ mtime_cache(scss_source_path) { Sass.compile_file(scss_source_path) }
148
149
  rescue Errno::ENOENT # Missing SCSS
149
150
  halt 404, "No such CSS or SCSS file found"
150
151
  rescue Exception => e # CSS syntax error or something alike
@@ -154,18 +155,64 @@ class Vitrine::App < Sinatra::Base
154
155
  end
155
156
  end
156
157
 
158
+ # Generate a sourcemap for CoffeeScript files
159
+ get /(.+)\.js\.map$/ do | basename |
160
+ begin
161
+ coffee_source = File.join(settings.root, 'public', "#{basename}.coffee")
162
+ content_type 'application/json', :charset => 'utf-8'
163
+ mtime_cache(coffee_source) do
164
+ Vitrine.build_coffeescript_source_map_body(coffee_source, File.join(settings.root, 'public'))
165
+ end
166
+ rescue Errno::ENOENT # Missing CoffeeScript
167
+ halt 404, "No coffeescript file found to generate the map for"
168
+ rescue Exception => e # CS syntax error or something alike
169
+ # inject it into the document
170
+ 'console.error(%s)' % [e.class, "\n", "--> ", e.message].join.inspect
171
+ end
172
+ end
173
+
157
174
  # Try to find CoffeeScript replacement for missing JS
158
- get /(.+)\.js/ do | basename |
175
+ get /(.+)\.js$/ do | basename |
159
176
  # If this file is not found resort back to a coffeescript
160
177
  begin
161
- coffee_source = File.read(File.join(settings.root, 'public', "#{basename}.coffee"))
178
+ coffee_source = File.join(settings.root, 'public', "#{basename}.coffee")
162
179
  content_type 'text/javascript', :charset => 'utf-8'
163
- CoffeeScript.compile(coffee_source)
180
+ mtime_cache(coffee_source) do
181
+ ["//# sourceMappingURL=#{basename}.js.map", CoffeeScript.compile(File.read(coffee_source))].join("\n")
182
+ end
164
183
  rescue Errno::ENOENT # Missing CoffeeScript
165
184
  halt 404, "No such JS file and could not find a .coffee replacement"
166
185
  rescue Exception => e # CS syntax error or something alike
167
186
  # inject it into the document
168
187
  'console.error(%s)' % [e.class, "\n", "--> ", e.message].join.inspect
169
188
  end
170
- end
189
+ end
190
+
191
+
192
+ def mtime_cache(path, &blk)
193
+ # Mix in the request URL into the cache key so that we can hash
194
+ # .map sourcemaps and .js compiles based off of the same file path
195
+ # and mtime
196
+
197
+ key = [File.expand_path(path), File.mtime(path), request.path_info, Vitrine::SEED]
198
+ cache_sha = Digest::SHA1.hexdigest(Marshal.dump(key))
199
+
200
+ p = File.join('/tmp', cache_sha)
201
+ if File.exist?(p)
202
+ return File.read(p)
203
+ else
204
+ Vitrine.atomic_write(p) do |f|
205
+ $stderr.puts "---> Recompiling #{path}"
206
+ body = yield
207
+ f.write(body)
208
+ return body
209
+ end
210
+ end
211
+ end
212
+
213
+ def get_layout
214
+ layouts = Dir.glob(File.join(settings.views, 'layout.*'))
215
+ layouts.any? ? :layout : false
216
+ end
217
+
171
218
  end
data/vitrine.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "vitrine"
8
- s.version = "0.0.7"
8
+ s.version = "0.0.9"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Julik Tarkhanov"]
12
- s.date = "2013-11-08"
12
+ s.date = "2013-11-11"
13
13
  s.description = " Serves ERB templates with live CoffeeScript and SASS "
14
14
  s.email = "me@julik.nl"
15
15
  s.executables = ["vitrine"]
@@ -24,6 +24,8 @@ Gem::Specification.new do |s|
24
24
  "README.rdoc",
25
25
  "Rakefile",
26
26
  "bin/vitrine",
27
+ "lib/atomic_write.rb",
28
+ "lib/sourcemaps.rb",
27
29
  "lib/version.rb",
28
30
  "lib/vitrine.rb",
29
31
  "test/helper.rb",
@@ -33,11 +35,11 @@ Gem::Specification.new do |s|
33
35
  s.homepage = "http://github.com/julik/vitrine"
34
36
  s.licenses = ["MIT"]
35
37
  s.require_paths = ["lib"]
36
- s.rubygems_version = "1.8.25"
38
+ s.rubygems_version = "2.0.6"
37
39
  s.summary = "Quickie micro-app preview server"
38
40
 
39
41
  if s.respond_to? :specification_version then
40
- s.specification_version = 3
42
+ s.specification_version = 4
41
43
 
42
44
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
45
  s.add_runtime_dependency(%q<sinatra>, ["~> 1.4"])
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vitrine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
5
- prerelease:
4
+ version: 0.0.9
6
5
  platform: ruby
7
6
  authors:
8
7
  - Julik Tarkhanov
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-11-08 00:00:00.000000000 Z
11
+ date: 2013-11-11 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: sinatra
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: coffee-script
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
@@ -46,7 +41,6 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: sass
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ~>
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ~>
60
53
  - !ruby/object:Gem::Version
@@ -62,39 +55,34 @@ dependencies:
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: guard
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :runtime
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rack-livereload
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :runtime
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - '>='
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rdoc
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - ~>
100
88
  - !ruby/object:Gem::Version
@@ -102,7 +90,6 @@ dependencies:
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - ~>
108
95
  - !ruby/object:Gem::Version
@@ -110,7 +97,6 @@ dependencies:
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: bundler
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
101
  - - ~>
116
102
  - !ruby/object:Gem::Version
@@ -118,7 +104,6 @@ dependencies:
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
108
  - - ~>
124
109
  - !ruby/object:Gem::Version
@@ -126,7 +111,6 @@ dependencies:
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: jeweler
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
115
  - - ~>
132
116
  - !ruby/object:Gem::Version
@@ -134,12 +118,11 @@ dependencies:
134
118
  type: :development
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
122
  - - ~>
140
123
  - !ruby/object:Gem::Version
141
124
  version: 1.8.7
142
- description: ! ' Serves ERB templates with live CoffeeScript and SASS '
125
+ description: ' Serves ERB templates with live CoffeeScript and SASS '
143
126
  email: me@julik.nl
144
127
  executables:
145
128
  - vitrine
@@ -154,6 +137,8 @@ files:
154
137
  - README.rdoc
155
138
  - Rakefile
156
139
  - bin/vitrine
140
+ - lib/atomic_write.rb
141
+ - lib/sourcemaps.rb
157
142
  - lib/version.rb
158
143
  - lib/vitrine.rb
159
144
  - test/helper.rb
@@ -162,29 +147,25 @@ files:
162
147
  homepage: http://github.com/julik/vitrine
163
148
  licenses:
164
149
  - MIT
150
+ metadata: {}
165
151
  post_install_message:
166
152
  rdoc_options: []
167
153
  require_paths:
168
154
  - lib
169
155
  required_ruby_version: !ruby/object:Gem::Requirement
170
- none: false
171
156
  requirements:
172
- - - ! '>='
157
+ - - '>='
173
158
  - !ruby/object:Gem::Version
174
159
  version: '0'
175
- segments:
176
- - 0
177
- hash: 3964899950062154621
178
160
  required_rubygems_version: !ruby/object:Gem::Requirement
179
- none: false
180
161
  requirements:
181
- - - ! '>='
162
+ - - '>='
182
163
  - !ruby/object:Gem::Version
183
164
  version: '0'
184
165
  requirements: []
185
166
  rubyforge_project:
186
- rubygems_version: 1.8.25
167
+ rubygems_version: 2.0.6
187
168
  signing_key:
188
- specification_version: 3
169
+ specification_version: 4
189
170
  summary: Quickie micro-app preview server
190
171
  test_files: []