tipsy 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -0
- data/README.md +2 -2
- data/Rakefile +10 -0
- data/bin/tipsy +16 -5
- data/lib/tipsy.rb +26 -14
- data/lib/tipsy/application.rb +14 -16
- data/lib/tipsy/builder.rb +17 -4
- data/lib/tipsy/builders/base.rb +64 -0
- data/lib/tipsy/builders/export.rb +16 -0
- data/lib/tipsy/builders/project.rb +40 -0
- data/lib/tipsy/builders/remote.rb +14 -0
- data/lib/tipsy/compressors/css.rb +11 -0
- data/lib/tipsy/compressors/javascript.rb +25 -0
- data/lib/tipsy/helpers.rb +24 -1
- data/lib/tipsy/helpers/asset_paths.rb +19 -0
- data/lib/tipsy/helpers/asset_tags.rb +32 -0
- data/lib/tipsy/helpers/capture.rb +33 -0
- data/lib/tipsy/helpers/sass.rb +40 -0
- data/lib/tipsy/helpers/tag.rb +12 -0
- data/lib/tipsy/logger.rb +54 -3
- data/lib/tipsy/project/Gemfile +8 -0
- data/lib/tipsy/project/config.erb +5 -2
- data/lib/tipsy/sass/template.rb +137 -0
- data/lib/tipsy/server.rb +50 -7
- data/lib/tipsy/version.rb +1 -1
- data/lib/tipsy/view.rb +24 -10
- data/test/fixtures/about.html +1 -0
- data/test/fixtures/contact.html +1 -0
- data/test/fixtures/index.html +1 -0
- data/test/functional/page_test.rb +33 -0
- data/test/root/{assets → development/assets}/javascripts/test.js +0 -0
- data/test/root/{assets → development/assets}/stylesheets/screen.css.scss +0 -0
- data/test/root/{config.rb → development/config.rb} +0 -0
- data/test/root/{views → development/views}/_layout.html.erb +0 -0
- data/test/root/{views → development/views}/index.html.erb +0 -0
- data/test/root/test/assets/javascripts/test.js +0 -0
- data/test/root/test/assets/stylesheets/screen.css.scss +3 -0
- data/test/root/test/config.rb +6 -0
- data/test/root/test/views/_layout.html.erb +1 -0
- data/test/root/test/views/about/index.html +1 -0
- data/test/root/test/views/contact.html +1 -0
- data/test/root/test/views/index.html.erb +1 -0
- data/test/test_helper.rb +33 -0
- data/test/unit/helpers/asset_paths_test.rb +14 -0
- data/test/unit/helpers_test.rb +22 -0
- data/test/unit/server_test.rb +1 -0
- data/tipsy.gemspec +5 -4
- metadata +83 -35
- data/config.ru +0 -26
- data/lib/tipsy/generator.rb +0 -53
data/Gemfile
CHANGED
@@ -3,3 +3,12 @@ gemspec
|
|
3
3
|
|
4
4
|
gem 'facades', :path => '/_Work/gems/facades'
|
5
5
|
gem 'thin'
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem 'jnunemaker-matchy', '~> 0.4.0', :require => 'matchy'
|
9
|
+
gem 'shoulda', '~> 2.11'
|
10
|
+
gem 'mocha', '~> 0.9.12'
|
11
|
+
gem 'rack-test'
|
12
|
+
gem 'turn'
|
13
|
+
gem 'minitest'
|
14
|
+
end
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
|
1
|
+
# Tipsy
|
2
2
|
|
3
3
|
Tipsy is a small Rack-based server inspired by gems like StaticMatic and Serve. Its purpose is to aid development of static sites by providing
|
4
4
|
Rails-esque style templating and helpers. Various template types are supported via the Tilt gem, and assets are served via Sprockets, essentially giving you
|
5
5
|
a miniture Rails "view-only" environment.
|
6
6
|
|
7
|
-
|
7
|
+
### Notes
|
8
8
|
|
9
9
|
Tipsy was developed for personal/internal use but feature/pull requests are gladly accepted. It is not designed to function in any kind of production
|
10
10
|
environment. When ready to upload files to a production environment, build the project and upload the result.
|
data/Rakefile
CHANGED
data/bin/tipsy
CHANGED
@@ -1,10 +1,21 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
libdir = File.dirname(__FILE__) + '/../lib'
|
4
|
+
if File.file?(libdir + '/tipsy/version.rb')
|
5
|
+
$LOAD_PATH.unshift(libdir)
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'tipsy'
|
10
|
+
rescue LoadError
|
11
|
+
require 'rubygems'
|
12
|
+
retry
|
13
|
+
end
|
14
|
+
|
15
|
+
if File.exists?(File.join(File.expand_path('.'), 'Gemfile'))
|
16
|
+
require 'bundler/setup'
|
17
|
+
Bundler.require(:default)
|
18
|
+
end
|
7
19
|
|
8
|
-
require 'tipsy'
|
9
20
|
Tipsy.root = File.expand_path('.')
|
10
21
|
Tipsy.run_command(ARGV, STDIN)
|
data/lib/tipsy.rb
CHANGED
@@ -8,17 +8,29 @@ module Tipsy
|
|
8
8
|
autoload :Application, 'tipsy/application'
|
9
9
|
autoload :Server, 'tipsy/server'
|
10
10
|
autoload :Responder, 'tipsy/handler'
|
11
|
+
autoload :Helpers, 'tipsy/helpers'
|
12
|
+
autoload :Builder, 'tipsy/builder'
|
13
|
+
autoload :Logger, 'tipsy/logger'
|
11
14
|
autoload :View, 'tipsy/view'
|
12
|
-
autoload :Helpers, 'tipsy/helpers'
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
module Compressors
|
17
|
+
autoload :CssCompressor, 'tipsy/compressors/css'
|
18
|
+
autoload :JavascriptCompressor, 'tipsy/compressors/javascript'
|
19
|
+
end
|
20
|
+
|
21
|
+
module Sass
|
22
|
+
autoload :Template, 'tipsy/sass/template'
|
23
|
+
end
|
24
|
+
|
17
25
|
mattr_accessor :root
|
18
26
|
mattr_accessor :logger
|
19
27
|
mattr_accessor :env
|
20
28
|
mattr_accessor :sprockets
|
21
29
|
mattr_accessor :compass
|
30
|
+
|
31
|
+
def self.logger
|
32
|
+
@logger ||= Tipsy::Logger.new($stdout)
|
33
|
+
end
|
22
34
|
|
23
35
|
def self.run_command(args, stdin)
|
24
36
|
args = [args].flatten
|
@@ -31,20 +43,20 @@ module Tipsy
|
|
31
43
|
end
|
32
44
|
|
33
45
|
args.shift
|
34
|
-
|
35
|
-
options.port = 4000
|
36
|
-
options.host = '0.0.0.0'
|
37
|
-
options.assets = []
|
38
|
-
options.build_path = File.join(Tipsy.root, 'build')
|
39
|
-
options.public_path = File.join(Tipsy.root, 'public')
|
40
|
-
options.asset_path = File.join(options.public_path, 'assets')
|
41
|
-
|
42
|
-
parse_options!
|
46
|
+
parse_options!
|
43
47
|
Tipsy::Application.send(:"#{to_run}", *args)
|
48
|
+
|
44
49
|
end
|
45
50
|
|
46
51
|
def self.options
|
47
|
-
@@options ||= OpenStruct.new
|
52
|
+
@@options ||= OpenStruct.new({
|
53
|
+
:port => 4000,
|
54
|
+
:host => '0.0.0.0',
|
55
|
+
:assets => OpenStruct.new({ :paths => [], :precompile => [] }),
|
56
|
+
:build_path => File.join(Tipsy.root, 'build'),
|
57
|
+
:public_path => File.join(Tipsy.root, 'public'),
|
58
|
+
:asset_path => File.join(Tipsy.root, 'public', 'assets')
|
59
|
+
})
|
48
60
|
end
|
49
61
|
|
50
62
|
private
|
data/lib/tipsy/application.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'rack'
|
2
|
-
require 'tipsy/server'
|
3
2
|
|
3
|
+
##
|
4
|
+
# Base class for all applications. Handles configuration of options,
|
5
|
+
# and processing of command line arguments.
|
6
|
+
#
|
4
7
|
module Tipsy
|
5
8
|
class Application
|
6
9
|
|
@@ -9,11 +12,15 @@ module Tipsy
|
|
9
12
|
|
10
13
|
def self.create(name = nil)
|
11
14
|
raise "Missing project name for 'tipsy new'" unless name
|
12
|
-
Tipsy::
|
15
|
+
Tipsy::Builder.build!(:project, name)
|
13
16
|
end
|
14
17
|
|
15
18
|
def self.build
|
16
|
-
Tipsy::Builder.
|
19
|
+
Tipsy::Builder.build!(:export)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.deploy
|
23
|
+
Tipsy::Builder.build!(:remote)
|
17
24
|
end
|
18
25
|
|
19
26
|
def self.initialize!
|
@@ -31,19 +38,10 @@ module Tipsy
|
|
31
38
|
end
|
32
39
|
|
33
40
|
def initialize
|
41
|
+
require 'tipsy/helpers/sass'
|
42
|
+
@app = Tipsy::Server.init!
|
34
43
|
|
35
|
-
|
36
|
-
use Rack::CommonLogger
|
37
|
-
use Rack::ShowStatus
|
38
|
-
use Rack::ShowExceptions
|
39
|
-
use Tipsy::StaticFile, :root => Tipsy.options.public_path, :urls => %w[/]
|
40
|
-
run Rack::Cascade.new([
|
41
|
-
Rack::URLMap.new({ "/#{File.basename(Tipsy.options.asset_path)}" => Tipsy::AssetHandler.new }),
|
42
|
-
Tipsy::Server.new
|
43
|
-
])
|
44
|
-
}
|
45
|
-
|
46
|
-
puts "Tipsy #{Tipsy::VERSION} running on #{config.address}:#{config.port}"
|
44
|
+
Tipsy.logger.info("Tipsy #{Tipsy::VERSION} running on #{config.address}:#{config.port}")
|
47
45
|
|
48
46
|
begin run_thin
|
49
47
|
rescue LoadError
|
@@ -79,7 +77,7 @@ module Tipsy
|
|
79
77
|
def run_webrick
|
80
78
|
handler = Rack::Handler.get('webrick')
|
81
79
|
handler.run app, server_opts do |server|
|
82
|
-
puts "Running Tipsy with Webrick. To use Mongrel or Thin, add them to your Gemfile"
|
80
|
+
puts "Running Tipsy with Webrick. To use Mongrel or Thin (recommended), add them to your Gemfile"
|
83
81
|
trap("INT"){ server.shutdown }
|
84
82
|
end
|
85
83
|
end
|
data/lib/tipsy/builder.rb
CHANGED
@@ -1,12 +1,25 @@
|
|
1
1
|
require 'active_support/inflector'
|
2
2
|
|
3
|
+
##
|
4
|
+
# Handles building source files into a final project, for
|
5
|
+
# either deployment or output to a directory
|
6
|
+
#
|
3
7
|
module Tipsy
|
4
|
-
|
8
|
+
module Builder
|
5
9
|
|
6
|
-
|
10
|
+
autoload :Base, 'tipsy/builders/base'
|
11
|
+
autoload :ProjectBuilder, 'tipsy/builders/project'
|
12
|
+
autoload :ExportBuilder, 'tipsy/builders/local'
|
13
|
+
autoload :RemoteBuilder, 'tipsy/builders/remote'
|
7
14
|
|
8
|
-
def
|
9
|
-
|
15
|
+
def self.build!(type = :project, *args)
|
16
|
+
handler = case type
|
17
|
+
when :project then ProjectBuilder.new(*args)
|
18
|
+
when :export then ExportBuilder.new(*args)
|
19
|
+
when :remote then RemoteBuilder.new(*args)
|
20
|
+
else raise 'No builder specified'
|
21
|
+
end
|
22
|
+
handler.build!
|
10
23
|
end
|
11
24
|
|
12
25
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Tipsy
|
2
|
+
module Builder
|
3
|
+
class Base
|
4
|
+
attr_reader :source_path, :dest_path
|
5
|
+
|
6
|
+
def excludes
|
7
|
+
@excludes ||= ['.git', '.gitignore', '.sass-cache', 'config.erb', '*.rb', '.', '..']
|
8
|
+
end
|
9
|
+
|
10
|
+
def build!
|
11
|
+
process_location(source_path, dest_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def excluded?(file)
|
17
|
+
return true if excludes.include?(file)
|
18
|
+
excludes.detect{ |exc| File.basename(exc).to_s.match(exc) }.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
def log_action(action, name)
|
22
|
+
name = name.gsub(dest_path, '').sub(/^\//, '')
|
23
|
+
Tipsy.logger.log_action(action, name)
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# By default make_file copies from one location to another
|
28
|
+
# Overridden in non-local scenarios
|
29
|
+
#
|
30
|
+
def make_file(source, destination)
|
31
|
+
log_action("create", destination)
|
32
|
+
FileUtils.cp(source, destination)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# By default make_folder makes a matching folder in destination from source
|
37
|
+
# Overridden in non-local scenarios
|
38
|
+
#
|
39
|
+
def make_folder(dirname)
|
40
|
+
log_action("create", dirname)
|
41
|
+
FileUtils.mkdir(dirname)
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Iterate through a file tree and process each file and folder.
|
46
|
+
#
|
47
|
+
def process_location(src, dest)
|
48
|
+
Dir.foreach(src) do |file|
|
49
|
+
next if excluded?(file)
|
50
|
+
source = File.join(src, file)
|
51
|
+
destination = File.join(dest, file)
|
52
|
+
|
53
|
+
if File.directory?(source)
|
54
|
+
make_folder(destination)
|
55
|
+
process_location(source, destination)
|
56
|
+
else
|
57
|
+
make_file(source, destination)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Tipsy
|
2
|
+
module Builder
|
3
|
+
class ExportBuilder < Base
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@source_path = Tipsy.root
|
7
|
+
@dest_path = Tipsy.options.build_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def build!
|
11
|
+
FileUtils.mkdir(dest_path) unless File.exists?(dest_path) && File.directory?(dest_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module Tipsy
|
5
|
+
module Builder
|
6
|
+
class ProjectBuilder < Base
|
7
|
+
attr_reader :project
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@project = name.camelize
|
11
|
+
@dest_path = File.join(Tipsy.root, name.underscore)
|
12
|
+
@source_path = File.expand_path("../../project", __FILE__)
|
13
|
+
end
|
14
|
+
|
15
|
+
def build!
|
16
|
+
|
17
|
+
FileUtils.mkdir(dest_path) unless File.exists?(dest_path)
|
18
|
+
super
|
19
|
+
cvars = Conf.new
|
20
|
+
cvars.root = dest_path
|
21
|
+
cvars.classname = @project
|
22
|
+
template = File.read(File.join(source_path, 'config.erb'))
|
23
|
+
config = ERB.new(template).result(cvars.get_binding)
|
24
|
+
|
25
|
+
File.open(File.join(dest_path, 'config.rb'), 'w'){ |io| io.write(config) }
|
26
|
+
log_action('create', File.join(dest_path, 'config.rb'))
|
27
|
+
|
28
|
+
Tipsy.logger.info("\n Project #{project} created in #{dest_path}.")
|
29
|
+
Tipsy.logger.info(" Run 'tipsy' from the root folder to start the server.\n\n")
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class Conf
|
34
|
+
attr_accessor :classname, :root
|
35
|
+
def get_binding; binding; end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
##
|
2
|
+
# Interface to Google's Online Closure Compiler.
|
3
|
+
# Uglifier is recommended (gem install uglifier) however to support environments where Node.js
|
4
|
+
# is unavailable this can be used as a fallback.
|
5
|
+
#
|
6
|
+
require 'net/http'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
module Tipsy
|
10
|
+
module Compressors
|
11
|
+
# http://closure-compiler.appspot.com/compile
|
12
|
+
class JavascriptCompressor
|
13
|
+
def compress(js)
|
14
|
+
return js if js.to_s.blank?
|
15
|
+
post_data = {
|
16
|
+
'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
|
17
|
+
'js_code' => js.to_s,
|
18
|
+
'output_format' => 'text'
|
19
|
+
}
|
20
|
+
request = Net::HTTP.post_form(URI.parse('http://closure-compiler.appspot.com/compile'), post_data)
|
21
|
+
request.body.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/tipsy/helpers.rb
CHANGED
@@ -1,9 +1,32 @@
|
|
1
|
+
require 'active_support/core_ext/array'
|
2
|
+
|
3
|
+
require 'tipsy/helpers/asset_paths'
|
1
4
|
require 'tipsy/helpers/capture'
|
2
5
|
require 'tipsy/helpers/tag'
|
6
|
+
require 'tipsy/helpers/asset_tags'
|
7
|
+
require 'tipsy/helpers/sass'
|
3
8
|
|
4
9
|
module Tipsy
|
5
10
|
module Helpers
|
11
|
+
extend ActiveSupport::Concern
|
6
12
|
include Capture
|
7
|
-
include Tag
|
13
|
+
include Tag
|
14
|
+
include AssetPaths
|
15
|
+
include AssetTags
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
private
|
19
|
+
|
20
|
+
def __initialize_helpers
|
21
|
+
module_names = []
|
22
|
+
includes = Dir.glob(File.expand_path(Tipsy.root) << "/helpers/*.rb").inject([]) do |arr, helper|
|
23
|
+
module_names << File.basename(helper, '.rb').classify
|
24
|
+
arr.concat File.open(helper).readlines
|
25
|
+
end
|
26
|
+
module_names.each{ |mod| includes.concat(["\n include #{mod}"]) }
|
27
|
+
self.class_eval(includes.join("\n"))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
8
31
|
end
|
9
32
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Tipsy
|
4
|
+
module Helpers
|
5
|
+
module AssetPaths
|
6
|
+
|
7
|
+
def asset_path(path)
|
8
|
+
return path if path.match(/^https?:/) || Pathname.new(path).absolute?
|
9
|
+
"/" << File.join('assets', path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def path_with_ext(path, ext)
|
13
|
+
return path if path.match(/^https?:/) || path.ends_with?(".#{ext}")
|
14
|
+
[path, ext].join('.')
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|