tipsy 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +6 -11
- data/README.md +24 -1
- data/Rakefile +13 -9
- data/bin/tipsy +4 -2
- data/lib/templates/server/htaccess.erb +14 -0
- data/lib/templates/site/Gemfile +19 -0
- data/lib/templates/site/assets/stylesheets/_config.css.scss +1 -0
- data/lib/templates/site/assets/stylesheets/screen.css.scss +1 -0
- data/lib/templates/site/config.rb +52 -0
- data/lib/templates/site/deploy.yml +27 -0
- data/lib/templates/site/layouts/default.html.erb +41 -0
- data/lib/templates/site/views/index.html.erb +2 -0
- data/lib/tipsy/compressors/{css.rb → css_compressor.rb} +0 -0
- data/lib/tipsy/compressors/javascript_compressor.rb +44 -0
- data/lib/tipsy/configuration.rb +9 -0
- data/lib/tipsy/handler/all.rb +4 -0
- data/lib/tipsy/handler/asset.rb +93 -0
- data/lib/tipsy/handler/erb.rb +42 -0
- data/lib/tipsy/handler/php.rb +36 -0
- data/lib/tipsy/{sass/template.rb → handler/sass/importer.rb} +15 -53
- data/lib/tipsy/handler/sass/resolver.rb +30 -0
- data/lib/tipsy/handler/sass.rb +36 -0
- data/lib/tipsy/handler/static.rb +30 -0
- data/lib/tipsy/helpers/asset_paths.rb +29 -1
- data/lib/tipsy/helpers/asset_tags.rb +1 -1
- data/lib/tipsy/helpers/capture.rb +12 -41
- data/lib/tipsy/helpers/rendering.rb +46 -0
- data/lib/tipsy/helpers/sass.rb +17 -6
- data/lib/tipsy/helpers/tag.rb +6 -9
- data/lib/tipsy/helpers.rb +13 -16
- data/lib/tipsy/runner.rb +82 -0
- data/lib/tipsy/runners/compiler.rb +189 -0
- data/lib/tipsy/runners/deployer.rb +7 -0
- data/lib/tipsy/runners/generator.rb +24 -0
- data/lib/tipsy/server.rb +56 -114
- data/lib/tipsy/site.rb +88 -0
- data/lib/tipsy/utils/logger.rb +47 -0
- data/lib/tipsy/utils/system.rb +115 -0
- data/lib/tipsy/utils/system_test.rb +103 -0
- data/lib/tipsy/version.rb +1 -1
- data/lib/tipsy/view/base.rb +55 -0
- data/lib/tipsy/view/context.rb +28 -0
- data/lib/tipsy/view/path.rb +44 -0
- data/lib/tipsy/view.rb +14 -68
- data/lib/tipsy.rb +30 -67
- data/{lib/tipsy/project/assets/javascripts/site.js → test/fixtures/capture.html.erb} +0 -0
- data/test/helpers/tag_test.rb +22 -0
- data/{lib/tipsy/project/assets/stylesheets/screen.css.scss → test/root/compiled/fake.txt} +0 -0
- data/test/root/{test/assets/javascripts/test.js → compiled/sub-path/fake.txt} +0 -0
- data/test/root/{development/assets/javascripts/test.js → compiled/sub-path-with-skip/fake.txt} +0 -0
- data/test/root/layouts/default.html.erb +0 -0
- data/test/root/views/index.html.erb +0 -0
- data/test/root/views/page.html.erb +0 -0
- data/test/root/views/sub/page.html.erb +0 -0
- data/test/root/views/sub/tertiary/index.html.erb +0 -0
- data/test/runner/compiler_test.rb +49 -0
- data/test/test_helper.rb +160 -21
- data/test/unit/site_test.rb +23 -0
- data/test/unit/tipsy_test.rb +13 -0
- data/test/unit/utils/system_test.rb +26 -0
- data/test/view/base_test.rb +34 -0
- data/test/view/path_test.rb +34 -0
- data/tipsy.gemspec +10 -7
- metadata +113 -84
- data/lib/tipsy/application.rb +0 -86
- data/lib/tipsy/builder.rb +0 -26
- data/lib/tipsy/builders/base.rb +0 -64
- data/lib/tipsy/builders/export.rb +0 -16
- data/lib/tipsy/builders/project.rb +0 -40
- data/lib/tipsy/builders/remote.rb +0 -14
- data/lib/tipsy/compressors/javascript.rb +0 -25
- data/lib/tipsy/logger.rb +0 -62
- data/lib/tipsy/project/Gemfile +0 -8
- data/lib/tipsy/project/config.erb +0 -19
- data/lib/tipsy/project/helpers/site_helper.rb +0 -4
- data/lib/tipsy/project/views/_layout.html.erb +0 -16
- data/test/fixtures/about.html +0 -1
- data/test/fixtures/contact.html +0 -1
- data/test/fixtures/index.html +0 -1
- data/test/functional/page_test.rb +0 -33
- data/test/root/.gitignore +0 -7
- data/test/root/development/assets/stylesheets/screen.css.scss +0 -3
- data/test/root/development/config.rb +0 -6
- data/test/root/development/views/_layout.html.erb +0 -20
- data/test/root/development/views/index.html.erb +0 -3
- data/test/root/test/assets/stylesheets/screen.css.scss +0 -3
- data/test/root/test/config.rb +0 -6
- data/test/root/test/views/_layout.html.erb +0 -1
- data/test/root/test/views/about/index.html +0 -1
- data/test/root/test/views/contact.html +0 -1
- data/test/root/test/views/index.html.erb +0 -1
- data/test/unit/helpers/asset_paths_test.rb +0 -14
- data/test/unit/helpers_test.rb +0 -22
- data/test/unit/server_test.rb +0 -1
data/lib/tipsy/server.rb
CHANGED
@@ -1,134 +1,76 @@
|
|
1
1
|
require 'rack'
|
2
|
-
require 'sprockets'
|
3
2
|
require 'hike'
|
4
3
|
|
5
|
-
module Tipsy
|
6
|
-
|
4
|
+
module Tipsy
|
5
|
+
##
|
6
|
+
# Rack server implementation.
|
7
|
+
# Tipsy::Server will run any Rack::Builder compatable format. If thin or mongrel
|
8
|
+
# are availble, they will be used first, and in that order, with a fallback to webrick.
|
9
|
+
#
|
7
10
|
class Server
|
11
|
+
attr_reader :request, :response
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
class << self
|
14
|
+
##
|
15
|
+
# Run the Rack::Builder application
|
16
|
+
# @param [run] Rack::Builder An instance of Rack::Builder
|
17
|
+
#
|
18
|
+
def run!(app, options)
|
19
|
+
begin
|
20
|
+
handler = Rack::Handler.get('thin')
|
21
|
+
handler.run app, options do |server|
|
22
|
+
puts "Running Tipsy with Thin (#{Thin::VERSION::STRING})."
|
23
|
+
end
|
24
|
+
exit(0)
|
25
|
+
rescue LoadError
|
26
|
+
begin
|
27
|
+
handler = Rack::Handler.get('mongrel')
|
28
|
+
handler.run app, options do |server|
|
29
|
+
puts "Running Tipsy with Mongrel (#{Mongrel::Const::MONGREL_VERSION})."
|
30
|
+
end
|
31
|
+
exit(0)
|
32
|
+
rescue LoadError
|
33
|
+
handler = Rack::Handler.get('webrick')
|
34
|
+
handler.run app, server_opts do |server|
|
35
|
+
puts "Running Tipsy with Webrick. To use Mongrel or Thin (recommended), add them to your Gemfile"
|
36
|
+
trap("INT"){ server.shutdown }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
23
41
|
end
|
24
|
-
|
42
|
+
|
25
43
|
def initialize
|
26
44
|
@last_update = Time.now
|
27
45
|
end
|
28
46
|
|
29
47
|
def call(env)
|
30
48
|
@request = Request.new(env)
|
31
|
-
@response = Response.new
|
32
|
-
|
33
|
-
|
34
|
-
content = view.render
|
35
|
-
content.nil? ? not_found : finish(content)
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def finish(content)
|
41
|
-
[ 200, { 'Content-Type' => 'text/html' }, [content] ]
|
42
|
-
end
|
43
|
-
|
44
|
-
def not_found
|
45
|
-
[ 400, { 'Content-Type' => 'text/html' }, [] ]
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
class AssetHandler < Sprockets::Environment
|
51
|
-
def initialize
|
52
|
-
Sprockets.register_engine '.scss', Tipsy::Sass::Template
|
53
|
-
|
54
|
-
super(Tipsy.root) do |env|
|
55
|
-
env.static_root = Tipsy.options.asset_path
|
56
|
-
#env.css_compressor = Tipsy::Compressors::CssCompressor.new
|
57
|
-
# begin
|
58
|
-
# require 'uglifier'
|
59
|
-
# env.js_compressor = Uglifier
|
60
|
-
# rescue LoadError
|
61
|
-
# env.js_compressor = Tipsy::Compressors::JavascriptCompressor.new
|
62
|
-
# end
|
63
|
-
end
|
64
|
-
Tipsy.sprockets = self
|
65
|
-
configure_paths!
|
66
|
-
self
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def configure_paths!
|
72
|
-
require 'compass'
|
73
|
-
require 'sass/plugin'
|
74
|
-
|
75
|
-
append_path "assets/javascripts"
|
76
|
-
append_path "assets/images"
|
77
|
-
append_path "assets/stylesheets"
|
78
|
-
|
79
|
-
compass_config = ::Compass::Configuration::Data.new("project")
|
80
|
-
compass_config.project_type = :rails
|
81
|
-
compass_config.project_path = Tipsy.root
|
82
|
-
compass_config.extensions_dir = Tipsy.root
|
83
|
-
compass_config.sass_dir = File.join("assets", "stylesheets")
|
84
|
-
|
85
|
-
::Sass::Plugin.engine_options.merge!(Compass.sass_engine_options)
|
86
|
-
|
87
|
-
Tipsy.options.assets.paths |= self.paths
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
# From the rack/contrib TryStatic class
|
94
|
-
class StaticFile
|
95
|
-
attr_reader :app, :try_files, :static
|
96
|
-
|
97
|
-
def initialize(app, options)
|
98
|
-
@app = app
|
99
|
-
@try_files = ['', *options.delete(:try)]
|
100
|
-
@static = ::Rack::Static.new(lambda { [404, {}, []] }, options)
|
49
|
+
@response = Response.new
|
50
|
+
result = Tipsy::View::Base.new(@request, @response)
|
51
|
+
result.render.to_a
|
101
52
|
end
|
102
53
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
54
|
+
##
|
55
|
+
# Subclass Rack::Request to create a rails-like params hash.
|
56
|
+
class Request < Rack::Request
|
57
|
+
def params
|
58
|
+
@params ||= begin
|
59
|
+
hash = HashWithIndifferentAccess.new.update(Rack::Utils.parse_nested_query(query_string))
|
60
|
+
post_params = form_data? ? Rack::Utils.parse_nested_query(body.read) : {}
|
61
|
+
hash.update(post_params) unless post_params.empty?
|
62
|
+
hash
|
63
|
+
end
|
64
|
+
end
|
111
65
|
end
|
112
|
-
end
|
113
66
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
hash = HashWithIndifferentAccess.new.update(Rack::Utils.parse_nested_query(query_string))
|
120
|
-
post_params = form_data? ? Rack::Utils.parse_nested_query(body.read) : {}
|
121
|
-
hash.update(post_params) unless post_params.empty?
|
122
|
-
hash
|
67
|
+
##
|
68
|
+
# Ensure proper body output
|
69
|
+
class Response < Rack::Response
|
70
|
+
def body=(value)
|
71
|
+
value.respond_to?(:each) ? super(value) : super([value])
|
123
72
|
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
class Response < Rack::Response
|
128
|
-
def body=(value)
|
129
|
-
value.respond_to?(:each) ? super(value) : super([value])
|
130
73
|
end
|
131
74
|
end
|
132
75
|
|
133
|
-
end
|
134
|
-
|
76
|
+
end
|
data/lib/tipsy/site.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'active_support/configurable'
|
2
|
+
|
3
|
+
module Tipsy
|
4
|
+
|
5
|
+
class Site
|
6
|
+
include ActiveSupport::Configurable
|
7
|
+
config_accessor :asset_path, :compile_to, :css_path, :javascripts_path, :images_path, :fonts_path,
|
8
|
+
:public_path, :load_paths, :compile_to, :compile
|
9
|
+
##
|
10
|
+
# Site configuration options
|
11
|
+
#
|
12
|
+
# General:
|
13
|
+
# port: The port in which the server should run
|
14
|
+
# address: The address on which the server should run
|
15
|
+
# public_path: Path to the public files/assets
|
16
|
+
#
|
17
|
+
# Assets:
|
18
|
+
# asset_path: The path in which assets should be preserved
|
19
|
+
# assets.paths: Paths in which sprockets will look for assets
|
20
|
+
# assets.javascripts_path: Path in which javascript files should be served. Helper methods will use this path
|
21
|
+
# assets.images_path: Path in which image assets should be served. Helper methods will use this path
|
22
|
+
# assets.css_path: Path in which stylesheets should be served. Helper methods will use this path
|
23
|
+
#
|
24
|
+
# Compiling:
|
25
|
+
# compile_path: The directory in which the site will be compiled
|
26
|
+
# compile.preserve: An array of files or directories that will be preserved when the compile folder is rebuilt.
|
27
|
+
|
28
|
+
config.port = 4000
|
29
|
+
config.address = '0.0.0.0'
|
30
|
+
|
31
|
+
config.public_path = File.join(Tipsy.root, 'public')
|
32
|
+
config.load_paths = ::ActiveSupport::OrderedOptions.new( 'assets' => [] )
|
33
|
+
config.asset_path = '/assets'
|
34
|
+
config.images_path = asset_path
|
35
|
+
config.fonts_path = "/fonts"
|
36
|
+
config.javascripts_path = asset_path
|
37
|
+
config.css_path = asset_path
|
38
|
+
config.compile_to = File.join(Tipsy.root, 'compiled')
|
39
|
+
|
40
|
+
config.compile = ::ActiveSupport::OrderedOptions.new
|
41
|
+
config.compile.assets = ['screen.css', 'site.js']
|
42
|
+
config.compile.preserve = [".svn", ".gitignore", ".git"]
|
43
|
+
config.compile.skip = []
|
44
|
+
|
45
|
+
|
46
|
+
config.compile.enable_rewrite = true
|
47
|
+
config.compile.rewrite_mode = :htaccess
|
48
|
+
|
49
|
+
def self.configure!
|
50
|
+
@_callbacks = { :before => [], :after => [] }
|
51
|
+
local_config = File.join(Tipsy.root, 'config.rb')
|
52
|
+
if File.exists?(local_config)
|
53
|
+
class_eval(File.open(local_config).readlines.join("\n"))
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Callback support
|
60
|
+
#
|
61
|
+
[:compile].each do |callback|
|
62
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
63
|
+
def self.before_#{callback}(&block)
|
64
|
+
if block_given?
|
65
|
+
@_callbacks[:before] << block
|
66
|
+
else
|
67
|
+
@_callbacks[:before].each(&:call)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.after_#{callback}(&block)
|
72
|
+
if block_given?
|
73
|
+
@_callbacks[:after] << block
|
74
|
+
else
|
75
|
+
@_callbacks[:after].each(&:call)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
METHOD
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def initialize
|
83
|
+
@_callbacks = {}
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Tipsy
|
2
|
+
module Utils
|
3
|
+
class Logger
|
4
|
+
COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33 }
|
5
|
+
attr_reader :stdout
|
6
|
+
|
7
|
+
def initialize(o)
|
8
|
+
@stdout = o
|
9
|
+
end
|
10
|
+
|
11
|
+
def print(msg)
|
12
|
+
puts msg
|
13
|
+
end
|
14
|
+
|
15
|
+
def action(name, action)
|
16
|
+
print colorize(:green, (name.rjust(12, ' ') << " "), :clear, action)
|
17
|
+
end
|
18
|
+
|
19
|
+
def info(msg)
|
20
|
+
print msg unless Tipsy.env.eql?("test")
|
21
|
+
end
|
22
|
+
|
23
|
+
def warn(msg)
|
24
|
+
print colorize(:yellow, "Warning: ", :clear, msg)
|
25
|
+
end
|
26
|
+
|
27
|
+
def error
|
28
|
+
print colorize(:red, "Error: ", :clear, msg)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def colorize(*args)
|
34
|
+
output = args.inject([]) do |arr, option|
|
35
|
+
unless option.is_a?(Symbol) && COLORS[option]
|
36
|
+
arr << option
|
37
|
+
else
|
38
|
+
arr << "\e[#{COLORS[option]}m"
|
39
|
+
end
|
40
|
+
arr
|
41
|
+
end
|
42
|
+
output.push("\e[0m").join("")
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Tipsy
|
6
|
+
module Utils
|
7
|
+
module System
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
def excludes
|
11
|
+
@_excludes ||= ['.svn', '.git', '.gitignore', '.sass-cache', 'config.erb', '.rb', '.DS_Store']
|
12
|
+
end
|
13
|
+
|
14
|
+
def excluded?(file, against = nil)
|
15
|
+
against ||= excludes
|
16
|
+
return true if file.to_s == '.' || file.to_s == '..' || against.include?(file)
|
17
|
+
check = ::Pathname.new(file)
|
18
|
+
return true if against.include?(check.basename.to_s)
|
19
|
+
!against.detect do |exc|
|
20
|
+
(check.basename == exc || check.extname == exc)
|
21
|
+
end.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Copies from one location to another
|
26
|
+
#
|
27
|
+
def copy_file(source, destination)
|
28
|
+
return true if skip_file?(source)
|
29
|
+
log_action("create", destination)
|
30
|
+
::FileUtils.cp(source, destination)
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Makes a matching folder in destination from source
|
35
|
+
#
|
36
|
+
def copy_folder(dirname)
|
37
|
+
return true if skip_path?(dirname)
|
38
|
+
log_action("create", dirname)
|
39
|
+
::FileUtils.mkdir(dirname)
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Basic alias
|
44
|
+
#
|
45
|
+
def mkdir_p(path)
|
46
|
+
return true if ::File.exists?(path)
|
47
|
+
log_action("create", path)
|
48
|
+
::FileUtils.mkdir_p(path)
|
49
|
+
end
|
50
|
+
|
51
|
+
def make_file(path, content)
|
52
|
+
::File.new(path, 'w').puts(content)
|
53
|
+
end
|
54
|
+
|
55
|
+
def rm_rf(path)
|
56
|
+
log_action('delete', path)
|
57
|
+
::FileUtils.rm_rf(path)
|
58
|
+
end
|
59
|
+
|
60
|
+
def unlink(file)
|
61
|
+
log_action('delete', file)
|
62
|
+
::File.unlink(file)
|
63
|
+
end
|
64
|
+
|
65
|
+
def empty_dir?(path)
|
66
|
+
::Dir.entries(path).reject do |ent|
|
67
|
+
ent == "." || ent == ".." || ent == path
|
68
|
+
end.empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Iterate through a file tree and process each file and folder.
|
73
|
+
#
|
74
|
+
def copy_tree(src, dest)
|
75
|
+
::Dir.foreach(src) do |file|
|
76
|
+
next if excluded?(file)
|
77
|
+
source = ::File.join(src, file)
|
78
|
+
destination = ::File.join(dest, file)
|
79
|
+
|
80
|
+
if ::File.directory?(source)
|
81
|
+
copy_folder(destination)
|
82
|
+
copy_tree(source, destination)
|
83
|
+
else
|
84
|
+
copy_file(source, destination)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Override in specific runner as necessary
|
90
|
+
# Allows more fine-grained control per directory.
|
91
|
+
def skip_path?(dirname)
|
92
|
+
false
|
93
|
+
end
|
94
|
+
|
95
|
+
# Override in specific runner as necessary.
|
96
|
+
# Allows more fine-grained control per file.
|
97
|
+
def skip_file?(filename)
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Collect the entire tree of files and folders and yield to a block
|
103
|
+
def enumerate_tree(path, &block)
|
104
|
+
::Find.find(path) do |path|
|
105
|
+
yield path
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def log_action(name, action)
|
110
|
+
::Tipsy.logger.action(name, action)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Tipsy
|
6
|
+
module Utils
|
7
|
+
##
|
8
|
+
# Overrides file and directory methods for the test environment
|
9
|
+
module SystemTest
|
10
|
+
attr_reader :deletions, :creations
|
11
|
+
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
include System
|
14
|
+
|
15
|
+
##
|
16
|
+
# Copies from one location to another
|
17
|
+
#
|
18
|
+
def copy_file(source, destination)
|
19
|
+
return true if skip_file?(source)
|
20
|
+
set_created(destination)
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Makes a matching folder in destination from source
|
25
|
+
#
|
26
|
+
def copy_folder(dirname)
|
27
|
+
return true if skip_path?(dirname)
|
28
|
+
log_action("create", dirname)
|
29
|
+
set_created(dirname)
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Basic alias
|
34
|
+
#
|
35
|
+
def mkdir_p(path)
|
36
|
+
return true if ::File.exists?(path)
|
37
|
+
log_action("create", path)
|
38
|
+
set_created(path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def make_file(path, content)
|
42
|
+
set_created(path)
|
43
|
+
end
|
44
|
+
|
45
|
+
def rm_rf(path)
|
46
|
+
log_action('delete', path)
|
47
|
+
set_deleted(path)
|
48
|
+
end
|
49
|
+
|
50
|
+
def unlink(file)
|
51
|
+
log_action('delete', file)
|
52
|
+
set_deleted(file)
|
53
|
+
end
|
54
|
+
|
55
|
+
def empty_dir?(path)
|
56
|
+
::Dir.entries(path).reject do |ent|
|
57
|
+
ent == "." || ent == ".." || ent == path || was_deleted?(File.join(path, ent))
|
58
|
+
end.empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Iterate through a file tree and process each file and folder.
|
63
|
+
#
|
64
|
+
def copy_tree(src, dest)
|
65
|
+
::Dir.foreach(src) do |file|
|
66
|
+
next if excluded?(file)
|
67
|
+
source = ::File.join(src, file)
|
68
|
+
destination = ::File.join(dest, file)
|
69
|
+
|
70
|
+
if ::File.directory?(source)
|
71
|
+
copy_folder(destination)
|
72
|
+
copy_tree(source, destination)
|
73
|
+
else
|
74
|
+
copy_file(source, destination)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def log_action(name, action)
|
81
|
+
end
|
82
|
+
|
83
|
+
def was_deleted?(path)
|
84
|
+
(@deletions ||= []).include?(path)
|
85
|
+
end
|
86
|
+
|
87
|
+
def was_created?(path)
|
88
|
+
(@creations ||= []).include?(path)
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def set_created(path)
|
94
|
+
(@creations ||= []) << path
|
95
|
+
end
|
96
|
+
|
97
|
+
def set_deleted(path)
|
98
|
+
(@deletions ||= []) << path
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/tipsy/version.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Tipsy
|
2
|
+
module View
|
3
|
+
class Base
|
4
|
+
|
5
|
+
attr_reader :lookup_context, :request, :response, :view_context, :template
|
6
|
+
|
7
|
+
def initialize(request, response)
|
8
|
+
@request = request
|
9
|
+
@response = response
|
10
|
+
@lookup_context = Tipsy::View::Path.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def render
|
14
|
+
|
15
|
+
@template = lookup_context.locate_template(current_path)
|
16
|
+
|
17
|
+
if template.nil?
|
18
|
+
return generate_response(nil)
|
19
|
+
end
|
20
|
+
|
21
|
+
@view_context = Tipsy::View::Context.new(request, lookup_context, File.dirname(template), lookup_context)
|
22
|
+
|
23
|
+
handler = Tilt[template]
|
24
|
+
tilt = handler.new(template, nil, :outvar => '@output_buffer')
|
25
|
+
result = tilt.render(view_context)
|
26
|
+
|
27
|
+
unless view_context.layout == false
|
28
|
+
layout = lookup_context.locate_layout(view_context.layout)
|
29
|
+
raise Tipsy::View::LayoutMissing.new("Missing layout '#{view_context.layout}'") and return if layout.nil?
|
30
|
+
wrapped = Tilt[layout].new(layout, nil, :outvar => '@output_buffer')
|
31
|
+
result = wrapped.render(view_context) do |*args|
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
generate_response(result)
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def current_path
|
43
|
+
@_current_path ||= request.path_info.to_s.sub(/^\//, '')
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_response(content)
|
47
|
+
response.status = ( content.nil? ? 404 : 200)
|
48
|
+
response.headers['content-type'] = "text/html"
|
49
|
+
response.body = content
|
50
|
+
response
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Tipsy
|
2
|
+
module View
|
3
|
+
##
|
4
|
+
# All views are rendered within a context object. This object handles
|
5
|
+
# transitioning data between templates and layouts.
|
6
|
+
#
|
7
|
+
class Context
|
8
|
+
include Tipsy::Helpers
|
9
|
+
attr_reader :request, :template, :layout, :virtual_path, :lookup_context
|
10
|
+
|
11
|
+
def initialize(request, template, path, lookup)
|
12
|
+
@request = request
|
13
|
+
@layout = 'default'
|
14
|
+
@template = template
|
15
|
+
@virtual_path = path
|
16
|
+
@lookup_context = lookup
|
17
|
+
@output_buffer = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def layout(set = nil)
|
21
|
+
@layout = set unless set.nil?
|
22
|
+
@layout
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'hike'
|
2
|
+
|
3
|
+
module Tipsy
|
4
|
+
module View
|
5
|
+
class Path < ::Hike::Trail
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
super(Tipsy.root)
|
9
|
+
append_path('.')
|
10
|
+
append_extensions '.erb','.html', '.json', '.xml'
|
11
|
+
end
|
12
|
+
|
13
|
+
def locate_template(view_path)
|
14
|
+
with_temporary_scope('views') do
|
15
|
+
@_template ||= (find(view_path) || find(File.join(view_path, "index")))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def locate_layout(name)
|
20
|
+
with_temporary_scope('layouts') do
|
21
|
+
@_layout ||= find(name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def locate_relative(path, name)
|
26
|
+
with_temporary_scope("views", path) do
|
27
|
+
find(name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def with_temporary_scope(*new_scope)
|
34
|
+
old_paths = @paths
|
35
|
+
new_scope = [Tipsy.root, new_scope].flatten
|
36
|
+
append_path(File.join(*new_scope))
|
37
|
+
yield
|
38
|
+
ensure
|
39
|
+
@paths = old_paths
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|