Rework the resin gem as a proper Sinatra extension

Fixes #4
This commit is contained in:
R. Tyler Croy 2012-11-28 20:42:53 -08:00
parent 9f0b97c288
commit 9c12ce4900
8 changed files with 289 additions and 113 deletions

View File

@ -1,93 +0,0 @@
require 'rubygems'
require 'sinatra/base'
require 'haml'
require File.expand_path(File.dirname(__FILE__) + '/helpers.rb')
AMBER_PATH = File.expand_path('../../../amber', __FILE__)
module Resin
def env
ENV['RACK_ENV']
end
module_function :env
def development?
!(env == 'production')
end
module_function :development?
class Server < Sinatra::Base
set :dump_errors, true
set :port, ENV['PORT'] || 4567
set :views, [File.join(Dir.pwd, 'views'), File.expand_path('../views', __FILE__)]
helpers do
include Resin::Helpers
end
before do
# Make sure drops are loaded
drops
end
get '/' do
haml :index
end
get '/:view/?' do |view|
begin
haml view.to_sym
rescue ::Errno::ENOENT
halt 404, 'Not found'
end
end
['js', 'css', 'images'].each do |path|
get "/#{path}/*" do |filename|
content_type_for_ext filename
data = load_resource(path, filename)
if data.nil? and path == 'js'
data = load_drop_resource(filename)
end
if data.nil?
halt 404, 'Not found'
end
data
end
end
if Resin.development?
set :logging, true
disable :protection
# Only enable the saving mechanism in test/development
put '*' do
unless request.body.nil?
filename = request.path.split('/')[-1]
directory = '/st/'
if filename.end_with? '.js'
directory = '/js/'
end
root_dir = Dir.pwd
if drops_filemap[filename]
drop_name = drops_filemap[filename]
root_dir = drops_map[drop_name]
end
path = File.join(root_dir, directory, filename)
puts ">> Commiting changes to #{path}"
File.open(path, 'w') do |fd|
request.body.each do |line|
fd.write(line)
end
end
end
end
end
end
end

View File

@ -4,7 +4,7 @@
Resin
= embed_amber
%body
- if Resin.development?
- if development?
%div{:style => 'float: right; clear: all'}
%button{:onclick => "smalltalk.Browser._open();"}
Run IDE

93
lib/sinatra/resin.rb Normal file
View File

@ -0,0 +1,93 @@
require 'sinatra/base'
require 'sinatra/resin/helpers'
require 'haml'
module Sinatra
module Resin
AMBER_PATH = File.expand_path('../../../amber', __FILE__)
def env
ENV['RACK_ENV']
end
module_function :env
def development?
!(env == 'production')
end
module_function :development?
def self.registered(app)
app.helpers Sinatra::Resin::Helpers
app.set :dump_errors, true
app.set :port, ENV['PORT'] || 4567
app.set :views, [File.join(Dir.pwd, 'views'), File.expand_path('../../resin/views', __FILE__)]
app.before do
# Make sure to call Sinatra::Resin::Helpers#drops to load all our drops
drops
end
app.get '/' do
haml :index
end
app.get '/:view/?' do |view|
begin
haml view.to_sym
rescue ::Errno::ENOENT
halt 404, 'Not found'
end
end
['js', 'css', 'images'].each do |path|
app.get "/#{path}/*" do |filename|
content_type_for_ext filename
data = load_resource(path, filename)
if data.nil? and path == 'js'
data = load_drop_resource(filename)
end
if data.nil?
halt 404, 'Not found'
end
data
end
end
if development?
app.set :logging, true
app.disable :protection
# Only enable the saving mechanism in test/development
app.put '*' do
unless request.body.nil?
filename = request.path.split('/')[-1]
directory = '/st/'
if filename.end_with? '.js'
directory = '/js/'
end
root_dir = Dir.pwd
if drops_filemap[filename]
drop_name = drops_filemap[filename]
root_dir = drops_map[drop_name]
end
path = File.join(root_dir, directory, filename)
puts ">> Commiting changes to #{path}"
File.open(path, 'w') do |fd|
request.body.each do |line|
fd.write(line)
end
end
end
end
end
end
end
register Resin
end

View File

@ -0,0 +1,171 @@
require 'json'
module Sinatra
module Resin
module Helpers
def self.append_js_file(filename, to_array)
filename = File.basename(filename)
if Sinatra::Resin.development?
unless filename.include? 'deploy'
to_array << filename
end
return
end
if (filename.include? 'deploy') && !(filename.include? '-Tests')
to_array << filename
end
end
def development?
Sinatra::Resin.development?
end
def javascript_files
files = []
# First our project's files take precedence
Dir.glob("#{Dir.pwd}/js/*.js") do |filename|
Sinatra::Resin::Helpers.append_js_file(filename, files)
end
# Then our drops get loaded
drops.each do |drop|
unless drop[:meta]
next
end
if drop[:js]
drop[:js].each do |filename|
Sinatra::Resin::Helpers.append_js_file(filename, files)
end
end
end
files
end
def find_template(views, name, engine, &block)
Array(views).each do |view|
super(view, name, engine, &block)
end
end
def embed_amber(options={})
deploy_line = ''
unless development?
deploy_line = "deploy: true,"
end
on_ready_function = options[:on_ready] || ''
return <<-END
<script type="text/javascript" src="/js/amber.js"></script>
<script type="text/javascript">
loadAmber({
#{deploy_line}
files : #{JSON.dump(javascript_files)},
prefix : 'js',
ready : function() { #{on_ready_function} }
});
</script>
END
end
def load_resource(prefix, filename)
# A file in our working directory will take precedence over the
# Amber-bundled files. This should allow custom Kernel-Objects.js files
# for example.
local_file = File.join(Dir.pwd, "#{prefix}/", filename)
amber_file = File.join(Sinatra::Resin::AMBER_PATH, "/#{prefix}/", filename)
if File.exists? local_file
File.open(local_file, 'r').read
elsif File.exists? amber_file
File.open(amber_file, 'r').read
else
nil
end
end
def load_drop_resource(filename)
drops.each do |drop|
if drop.nil? or drop.empty? or drop[:js].empty?
next
end
drop[:js].each do |drop_filepath|
drop_filename = File.basename(drop_filepath)
if filename == drop_filename
return File.open(drop_filepath).read
end
end
end
nil
end
def content_type_for_ext(filename)
if File.extname(filename) == '.js'
content_type 'application/javascript'
elsif File.extname(filename) == '.css'
content_type 'text/css'
else
content_type 'text/plain'
end
end
def load_drop_file(filepath)
YAML::load(File.open(filepath).read)
end
def self.flush_drops
@@drops = nil
@@drops_map = {}
@@drops_filemap = {}
end
def drops_map
@@drops_map
end
def drops_filemap
@@drops_filemap
end
def drops
@@drops ||= begin
@@drops_map ||= {}
@@drops_filemap ||= {}
drops_path = File.join(Dir.pwd, 'drops')
loaded = []
Dir.glob("#{drops_path}/*/drop.yml") do |filename|
drop = load_drop_file(filename)
if drop.nil? or drop.empty?
next
end
drop_dir = File.dirname(filename)
name = drop['drop']['name']
puts ">>> Loading Resin Drop: #{name}"
data = {:meta => drop['drop'],
:js => Dir[File.join(drop_dir, 'js', '*.js')],
:st => Dir[File.join(drop_dir, 'st', '*.st')]
}
loaded << data
@@drops_map[name] = drop_dir
data[:js].each do |js|
@@drops_filemap[File.basename(js)] = name
end
data[:st].each do |st|
@@drops_filemap[File.basename(st)] = name
end
end
loaded
end
end
end
end
end

View File

@ -2,7 +2,7 @@
spec = Gem::Specification.new do |s|
s.name = 'resin'
s.version = '0.2.3'
s.version = '0.3.0'
s.author = "R. Tyler Croy"
s.email = "tyler@linux.com"
s.homepage = "https://github.com/rtyler/resin"

View File

@ -1,9 +1,8 @@
require File.dirname(__FILE__) + '/spec_helper'
require 'spec_helper'
describe Resin do
describe Sinatra::Resin do
def app
Resin::Server
FakeApp
end
it 'generates an index page' do
@ -23,18 +22,18 @@ describe Resin do
describe '#development?' do
it 'should be false when in production' do
Resin.should_receive(:env).and_return('production')
Resin.development?.should be false
Sinatra::Resin.should_receive(:env).and_return('production')
Sinatra::Resin.development?.should be false
end
it 'should be true when in development' do
Resin.should_receive(:env).and_return('development')
Resin.development?.should be true
Sinatra::Resin.should_receive(:env).and_return('development')
Sinatra::Resin.development?.should be true
end
it 'should be true by default (i.e. no RACK_ENV)' do
Resin.should_receive(:env).and_return(nil)
Resin.development?.should be true
Sinatra::Resin.should_receive(:env).and_return(nil)
Sinatra::Resin.development?.should be true
end
end
end

View File

@ -1,7 +1,7 @@
require File.dirname(__FILE__) + '/spec_helper'
require 'spec_helper'
describe Resin::Helpers do
include Resin::Helpers
describe Sinatra::Resin::Helpers do
include Sinatra::Resin::Helpers
describe '#javascript_files' do
# Stub out the #drops method for these tests
@ -29,13 +29,13 @@ describe Resin::Helpers do
end
it 'should only include deploy files when in production' do
Resin.stub(:development?).and_return(false)
Sinatra::Resin.stub(:development?).and_return(false)
Dir.stub(:glob).and_yield('hello.deploy.js').and_yield('ignore.js')
javascript_files.should == ["hello.deploy.js"]
end
it 'should exclude -Tests files when in production' do
Resin.stub(:development?).and_return(false)
Sinatra::Resin.stub(:development?).and_return(false)
Dir.stub(:glob).and_yield('Hello-Tests.deploy.js').and_yield('Hello.deploy.js')
javascript_files.should == ["Hello.deploy.js"]
end
@ -43,8 +43,9 @@ describe Resin::Helpers do
describe '#drops' do
before :each do
Resin::Helpers.flush_drops
Sinatra::Resin::Helpers.flush_drops
end
it 'should return nil if there are no drops available' do
Dir.stub(:glob)
drops.should be_instance_of(Array)

View File

@ -2,8 +2,9 @@ require 'rubygems'
require 'rspec'
require 'rack/test'
require File.join(File.dirname(__FILE__), "/../lib/resin/app.rb")
require File.join(File.dirname(__FILE__), "/../lib/resin/helpers.rb")
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib/')
require 'sinatra/resin'
Sinatra::Base.set :environment, :test
Sinatra::Base.set :run, false
@ -13,3 +14,7 @@ Sinatra::Base.set :logging, false
RSpec.configure do |conf|
conf.include Rack::Test::Methods
end
class FakeApp < Sinatra::Base
register Sinatra::Resin
end