scharfie-bones 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +38 -0
- data/bin/bones +22 -0
- data/bones.gemspec +37 -0
- data/lib/Rakefile +3 -0
- data/lib/bones.rb +193 -0
- data/lib/boot.rb +34 -0
- data/lib/cache.rb +105 -0
- data/lib/extensions.rb +26 -0
- data/lib/helpers/core_helper.rb +140 -0
- data/lib/init.rb +70 -0
- data/lib/pages/directory.html.erb +5 -0
- data/lib/pages/intro.html.erb +28 -0
- data/lib/server.rb +42 -0
- data/lib/tasks/bones.rb +28 -0
- metadata +85 -0
data/README
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
Bones, the simple HTML mockup framework.
|
2
|
+
|
3
|
+
What it does:
|
4
|
+
|
5
|
+
- Provides a simple framework for creating views
|
6
|
+
without worrying about controllers
|
7
|
+
- Allows the building of a complete static website
|
8
|
+
out of views, partials, and layouts which can
|
9
|
+
then be combined into full HTML pages for deployment
|
10
|
+
onto ANY webserver.
|
11
|
+
|
12
|
+
Requirements:
|
13
|
+
|
14
|
+
- ActiveSupport
|
15
|
+
- rack
|
16
|
+
|
17
|
+
Starting it up:
|
18
|
+
|
19
|
+
- Install
|
20
|
+
sudo gem install scharfie-bones -s http://gems.github.com
|
21
|
+
|
22
|
+
- Generate:
|
23
|
+
bones my_bones_app
|
24
|
+
cd my_bones_app
|
25
|
+
|
26
|
+
- Serve
|
27
|
+
rake server
|
28
|
+
|
29
|
+
- Browse:
|
30
|
+
http://localhost:3000
|
31
|
+
|
32
|
+
Flatten your views into .html files:
|
33
|
+
|
34
|
+
- Cache with our without versioning
|
35
|
+
rake cache:simple # without versioning
|
36
|
+
rake cache:versioned # with versioning
|
37
|
+
|
38
|
+
Then upload the entire public/ directory to your server.
|
data/bin/bones
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# $:.unshift(File.dirname(__FILE__) + '/../')
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
path = ARGV.shift
|
6
|
+
|
7
|
+
if path.nil?
|
8
|
+
puts "Please supply a path to create a bones application."
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
|
12
|
+
# Ensure given path exists
|
13
|
+
path = File.expand_path(path)
|
14
|
+
FileUtils.mkdir(path) unless File.directory?(path)
|
15
|
+
|
16
|
+
# Set the root to the path
|
17
|
+
ROOT = path
|
18
|
+
|
19
|
+
require 'boot.rb'
|
20
|
+
require 'init.rb'
|
21
|
+
|
22
|
+
BonesInitializer.run
|
data/bones.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "bones"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.date = "2008-08-22"
|
5
|
+
|
6
|
+
s.summary = "Simple HTML mockup framework for designers using ERB"
|
7
|
+
s.description = "Simple HTML mockup framework for designers using ERB"
|
8
|
+
s.email = "scharfie@gmail.com"
|
9
|
+
s.homepage = "http://github.com/scharfie/bones"
|
10
|
+
s.has_rdoc = false
|
11
|
+
s.authors = ["Chris Scharf", "Ryan Heath"]
|
12
|
+
|
13
|
+
s.require_paths = ['lib']
|
14
|
+
s.default_executable = 'bones'
|
15
|
+
s.executables = ['bones']
|
16
|
+
|
17
|
+
s.files = [
|
18
|
+
'README',
|
19
|
+
'bin/bones',
|
20
|
+
'lib/bones.rb',
|
21
|
+
'lib/boot.rb',
|
22
|
+
'lib/cache.rb',
|
23
|
+
'lib/extensions.rb',
|
24
|
+
'lib/helpers',
|
25
|
+
'lib/helpers/core_helper.rb',
|
26
|
+
'lib/init.rb',
|
27
|
+
'lib/pages/directory.html.erb',
|
28
|
+
'lib/pages/intro.html.erb',
|
29
|
+
'lib/Rakefile',
|
30
|
+
'lib/server.rb',
|
31
|
+
'lib/tasks/bones.rb',
|
32
|
+
'bones.gemspec'
|
33
|
+
]
|
34
|
+
|
35
|
+
s.add_dependency("rack", [">= 0.3.0"])
|
36
|
+
s.add_dependency("activesupport", [">= 2.1.0"])
|
37
|
+
end
|
data/lib/Rakefile
ADDED
data/lib/bones.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
# Bones - the _real_ request handler,
|
2
|
+
# which BonesProxy loads and calls upon to
|
3
|
+
# do the dirty work.
|
4
|
+
class Bones
|
5
|
+
# Process incoming request (for real this time!)
|
6
|
+
def call(env)
|
7
|
+
# Grab the request
|
8
|
+
request = Rack::Request.new(env)
|
9
|
+
|
10
|
+
# Create a new template for the given path
|
11
|
+
# and compile it
|
12
|
+
template = Template.new(request.path_info)
|
13
|
+
output = template.compile
|
14
|
+
|
15
|
+
# Build a rack response
|
16
|
+
Rack::Response.new.finish do |response|
|
17
|
+
response.write output
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns array of all pages (excluding partials)
|
22
|
+
def self.pages
|
23
|
+
Dir.chdir(PAGES) do
|
24
|
+
Dir.glob('**/*.html.erb').map do |f|
|
25
|
+
f.starts_with?('_') ? nil : f.gsub('.html.erb', '')
|
26
|
+
end.compact
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Template - loads template file based on
|
31
|
+
# request path information and compiles
|
32
|
+
# it using ERB
|
33
|
+
class Template
|
34
|
+
attr_accessor :path
|
35
|
+
attr_accessor :layout
|
36
|
+
attr_accessor :options
|
37
|
+
|
38
|
+
# Load all available helpers
|
39
|
+
def self.include_helpers
|
40
|
+
files = [
|
41
|
+
Dir.glob(SYSTEM / 'helpers/*_helper.rb'),
|
42
|
+
Dir.glob(ROOT / 'helpers/*_helper.rb')
|
43
|
+
].flatten
|
44
|
+
|
45
|
+
# Include each helper
|
46
|
+
files.each do |filename|
|
47
|
+
klass = File.basename(filename, '.rb').camelize
|
48
|
+
force_load klass => filename
|
49
|
+
include klass.constantize
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Load the helpers
|
54
|
+
include_helpers if Object.const_defined?(:SYSTEM)
|
55
|
+
|
56
|
+
# Initialize template with path and optional layout
|
57
|
+
def initialize(path, layout=-1, options={})
|
58
|
+
@path = path.gsub(/\.html|\.html\.erb/, '')
|
59
|
+
@layout = layout == -1 ? 'application' : layout
|
60
|
+
@options = options
|
61
|
+
end
|
62
|
+
|
63
|
+
# Full path to template file
|
64
|
+
def filename
|
65
|
+
if @path =~ /raw$/
|
66
|
+
layout false
|
67
|
+
path = SYSTEM / 'pages' / 'directory.html.erb'
|
68
|
+
else
|
69
|
+
path = PAGES / @path
|
70
|
+
path /= 'index' if File.directory?(path) or path.ends_with?('/')
|
71
|
+
path += '.html.erb'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns array of pages
|
76
|
+
def pages
|
77
|
+
Bones.pages
|
78
|
+
end
|
79
|
+
|
80
|
+
# Full path to layout file
|
81
|
+
def layout_filename
|
82
|
+
path = LAYOUTS / layout.to_s + '.html.erb'
|
83
|
+
end
|
84
|
+
|
85
|
+
# Gets/sets layout
|
86
|
+
# If no argument is passed, the layout is returned;
|
87
|
+
# otherwise, sets the layout
|
88
|
+
# (use false or nil to turn off the layout)
|
89
|
+
def layout(arg=-1)
|
90
|
+
@layout = arg unless arg == -1
|
91
|
+
@layout
|
92
|
+
end
|
93
|
+
|
94
|
+
# Compiles the template (along with the layout
|
95
|
+
# if necessary)
|
96
|
+
def compile
|
97
|
+
src = ERB.new(File.read(filename)).src
|
98
|
+
src = (local_assigns_source || '') + (src || '')
|
99
|
+
@content_for_layout = eval(src) # erb.result(binding)
|
100
|
+
|
101
|
+
if layout
|
102
|
+
erb = ERB.new(File.read(layout_filename))
|
103
|
+
erb.result(binding)
|
104
|
+
else
|
105
|
+
@content_for_layout
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Generates source for local variable assignments
|
110
|
+
def local_assigns_source
|
111
|
+
src = []
|
112
|
+
(options[:locals] || {}).each do |key, value|
|
113
|
+
src << "#{key} = #{value.inspect};\n"
|
114
|
+
end
|
115
|
+
src.join
|
116
|
+
end
|
117
|
+
|
118
|
+
# Short-hand for compiling a template
|
119
|
+
def self.compile(*args)
|
120
|
+
Template.new(*args).compile
|
121
|
+
end
|
122
|
+
|
123
|
+
# Renders partial template - an underscore
|
124
|
+
# is automatically added to the passed name,
|
125
|
+
# so <%= partial 'footer' %> will render
|
126
|
+
# the '_footer.html.erb' template.
|
127
|
+
def partial(name, options={})
|
128
|
+
path = name.to_s.split('/')
|
129
|
+
path[-1] = '_' + path.last unless path.last.starts_with?('_')
|
130
|
+
name = path.join('/')
|
131
|
+
Template.compile(name, false, options)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Class used to encapsulate the logic needed to
|
136
|
+
# maintain mockup versions
|
137
|
+
class Versioned
|
138
|
+
# Pre-fix used for versioned directories
|
139
|
+
DIR_PREFIX = 'v'
|
140
|
+
|
141
|
+
# Start with the original destination
|
142
|
+
def initialize(original_destination)
|
143
|
+
@original_destination = original_destination
|
144
|
+
@versioned_destination = nil
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns the new destination, which depends on
|
148
|
+
# the existing amount of 'versions'
|
149
|
+
def destination
|
150
|
+
@versioned_destination ||= get_versioned_destination
|
151
|
+
end
|
152
|
+
|
153
|
+
# Transfers all public directories to the new 'versioned'
|
154
|
+
# directory, so each version can contain it's own mockup
|
155
|
+
# (note: only copies asset directories - ignores "v1", "v2", etc)
|
156
|
+
def copy_public_directories
|
157
|
+
public_directories.each do |src|
|
158
|
+
FileUtils.copy_entry ROOT / 'public' / src, destination / src
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns the versioned directories within the 'public' folder
|
163
|
+
# $> Bones::Versioned.directories
|
164
|
+
# $> => ["/v1", "/v2", ... "/vN"]
|
165
|
+
def self.directories
|
166
|
+
Dir.glob(ROOT / 'public' / "#{DIR_PREFIX}**").inject([]) do |dirs, dir|
|
167
|
+
dirs << '/' + dir.gsub(/^\/.+\//, '')
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Public accessor of version
|
172
|
+
def version
|
173
|
+
next_version
|
174
|
+
end
|
175
|
+
|
176
|
+
# Returns directory name of versioned path
|
177
|
+
# For example, 'v1'
|
178
|
+
def versioned_directory_name
|
179
|
+
DIR_PREFIX + next_version
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
# increments to the next version based on existing versions
|
184
|
+
def next_version
|
185
|
+
(self.class.directories.size + 1).to_s
|
186
|
+
end
|
187
|
+
|
188
|
+
# constructs the next version path
|
189
|
+
def get_versioned_destination
|
190
|
+
@original_destination /= versioned_directory_name
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
data/lib/boot.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
SYSTEM = File.dirname(__FILE__)
|
2
|
+
ROOT = File.expand_path('.') unless Object.const_defined?(:ROOT)
|
3
|
+
PAGES = File.join(ROOT, 'pages')
|
4
|
+
LAYOUTS = File.join(ROOT, 'layouts')
|
5
|
+
|
6
|
+
$:.unshift(SYSTEM)
|
7
|
+
$:.unshift(File.join(ROOT, 'lib'))
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'yaml'
|
11
|
+
require 'rack'
|
12
|
+
require 'rack/request'
|
13
|
+
require 'rack/response'
|
14
|
+
require 'activesupport'
|
15
|
+
require 'extensions'
|
16
|
+
require 'erb'
|
17
|
+
require 'bones'
|
18
|
+
|
19
|
+
def directories(base)
|
20
|
+
Dir.chdir(base) do
|
21
|
+
Dir.entries(base).map do |e|
|
22
|
+
next if e =~ /^\.+$/
|
23
|
+
File.directory?(base / e) ? '/' + e : nil
|
24
|
+
end.compact
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def page_directories
|
29
|
+
directories(ROOT / 'pages')
|
30
|
+
end
|
31
|
+
|
32
|
+
def public_directories
|
33
|
+
directories(ROOT / 'public') - page_directories - Bones::Versioned.directories
|
34
|
+
end
|
data/lib/cache.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require File.join(File.dirname(__FILE__), 'boot')
|
3
|
+
require 'fileutils'
|
4
|
+
require 'bones'
|
5
|
+
require 'optparse'
|
6
|
+
require 'ostruct'
|
7
|
+
|
8
|
+
# Argument processor
|
9
|
+
class CacheOptions < OpenStruct
|
10
|
+
# Default options
|
11
|
+
def self.default_options
|
12
|
+
returning new do |o|
|
13
|
+
o.destination = ROOT / 'public' # Set original destination
|
14
|
+
o.versioned = false # No versions by default
|
15
|
+
o.base = '' # Base URL is empty
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Process arguments
|
20
|
+
def self.process(args)
|
21
|
+
options = default_options
|
22
|
+
|
23
|
+
OptionParser.new do |o|
|
24
|
+
o.on('--versioned', '--versions', "Enable versioning") do
|
25
|
+
options.versioned = Bones::Versioned.new(options.destination)
|
26
|
+
end
|
27
|
+
|
28
|
+
o.on('--base PATH', "Change the base URL path") do |path|
|
29
|
+
options.base = path
|
30
|
+
end
|
31
|
+
|
32
|
+
o.on_tail("-h", "--help", "Show this message") do
|
33
|
+
puts o
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end.parse!(args)
|
37
|
+
|
38
|
+
options
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns true if the versions enabled
|
42
|
+
def versioned?
|
43
|
+
versioned != false
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns destination
|
47
|
+
def destination
|
48
|
+
versioned? ? versioned.destination : super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Process arguments
|
53
|
+
options = CacheOptions.process(ARGV)
|
54
|
+
|
55
|
+
# Fixes the given URL path to begin at given base.
|
56
|
+
# In addition, the .html extension will be added if
|
57
|
+
# the path is a page.
|
58
|
+
#
|
59
|
+
# For example, if the base is /some_folder,
|
60
|
+
# normalize_url('/page_path', '/some_folder')
|
61
|
+
# # => /some_folder/page_path.html
|
62
|
+
def normalize_url(path, base='')
|
63
|
+
@known_pairs ||= {}
|
64
|
+
@public_directories_regex ||= Regexp.new(public_directories.join('|'))
|
65
|
+
|
66
|
+
if v = @known_pairs[path]
|
67
|
+
return v
|
68
|
+
else
|
69
|
+
value = case
|
70
|
+
when path =~ @public_directories_regex
|
71
|
+
path
|
72
|
+
when File.directory?('pages' / path)
|
73
|
+
path
|
74
|
+
else
|
75
|
+
path + '.html'
|
76
|
+
end
|
77
|
+
|
78
|
+
@known_pairs[path] = base / value
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
version = options.versioned? ? options.versioned.versioned_directory_name : nil
|
83
|
+
|
84
|
+
# Process each page
|
85
|
+
Dir.chdir(ROOT) do
|
86
|
+
Bones.pages.each do |page|
|
87
|
+
puts "** Generating #{[version, page].compact.join('/')}.html"
|
88
|
+
result = Bones::Template.compile(page)
|
89
|
+
result.gsub!(/(href|src|action)="([-A-Za-z0-9_\.\/]+)(.*?)"/) do |match|
|
90
|
+
property, url, params = $1, normalize_url(original_url = $2, options.base), $3
|
91
|
+
'%s="%s%s"' % [property, url, params]
|
92
|
+
end
|
93
|
+
|
94
|
+
path = options.destination / page + '.html'
|
95
|
+
FileUtils.mkdir_p(File.dirname(path))
|
96
|
+
File.open(path, 'w') { |f| f.write(result) }
|
97
|
+
end
|
98
|
+
|
99
|
+
if options.versioned?
|
100
|
+
puts "** Copying public files"
|
101
|
+
options.versioned.copy_public_directories
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
puts "** Done."
|
data/lib/extensions.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class String
|
2
|
+
# Join strings using /
|
3
|
+
# (i.e. "system" / "pages" -> "system/pages")
|
4
|
+
def /(other)
|
5
|
+
File.join(self, other)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# Loads filename, removing the associated
|
10
|
+
# class if defined
|
11
|
+
#
|
12
|
+
# Arguments:
|
13
|
+
# hash of 'Class' => 'filename' pairs
|
14
|
+
#
|
15
|
+
# Example:
|
16
|
+
#
|
17
|
+
# force_load 'Application' => 'application.rb'
|
18
|
+
#
|
19
|
+
# will remove the Application class if found,
|
20
|
+
# and then load the application.rb file
|
21
|
+
def force_load(map={})
|
22
|
+
map.each do |klass, filename|
|
23
|
+
Class.remove_class(klass) if Object.const_defined?(klass)
|
24
|
+
load filename
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
module CoreHelper
|
2
|
+
module HTML
|
3
|
+
# Creates a tag with content and properties
|
4
|
+
# Example:
|
5
|
+
# content_tag(:div, "Hello", :id => 'greeting')
|
6
|
+
# -- generates --
|
7
|
+
# <div id="greeting">Hello</div>
|
8
|
+
def content_tag(name, *arguments, &block)
|
9
|
+
name = name.to_s
|
10
|
+
options = Hash === arguments.last ? arguments.pop : {}
|
11
|
+
properties = html_options_from_hash(options)
|
12
|
+
|
13
|
+
result = ["<#{name}"]
|
14
|
+
result << ' ' + properties unless properties.empty?
|
15
|
+
|
16
|
+
if short_tag_names.include?(name)
|
17
|
+
result << ' />'
|
18
|
+
else
|
19
|
+
result << '>'
|
20
|
+
result << arguments.join
|
21
|
+
result << capture(&block) if block_given?
|
22
|
+
result << "</#{name}>"
|
23
|
+
end
|
24
|
+
|
25
|
+
result = result.join('')
|
26
|
+
concat(result, block.binding) if block_given?
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns array of tag names that can be
|
31
|
+
# closed with /> instead of </tagname>
|
32
|
+
def short_tag_names
|
33
|
+
%w(input br link hr img)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Converts hash of options into a string of HTML
|
37
|
+
# property="value" pairs
|
38
|
+
def html_options_from_hash(options={})
|
39
|
+
options.map do |key, value|
|
40
|
+
%Q{#{key}="#{value}"}
|
41
|
+
end.sort.join(' ')
|
42
|
+
end
|
43
|
+
|
44
|
+
# Creates link tag to stylesheet(s)
|
45
|
+
# (options are support as the last argument)
|
46
|
+
def stylesheet_link_tag(*sources)
|
47
|
+
return nil if sources.empty?
|
48
|
+
options = Hash === sources.last ? sources.pop : {}
|
49
|
+
result = sources.map { |e| stylesheet_tag(e, options) }
|
50
|
+
result.join("\n")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Creates a stylesheet link tag
|
54
|
+
def stylesheet_tag(name, options={})
|
55
|
+
name += '.css' unless name =~ /\./
|
56
|
+
options.reverse_merge! :href => "/stylesheets/#{name}",
|
57
|
+
:rel => 'stylesheet', :type => 'text/css'
|
58
|
+
|
59
|
+
content_tag :link, options
|
60
|
+
end
|
61
|
+
|
62
|
+
# Creates script tag to javascript(s)
|
63
|
+
# (options are support as the last argument)
|
64
|
+
def javascript_include_tag(*sources)
|
65
|
+
return nil if sources.empty?
|
66
|
+
options = Hash === sources.last ? sources.pop : {}
|
67
|
+
sources.collect { |e| javascript_tag(e, options) }.join("\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
# Creates a javascript script tag
|
71
|
+
def javascript_tag(name, options={})
|
72
|
+
name += '.js' unless name =~ /\./
|
73
|
+
options.merge! :src => "/javascripts/#{name}",
|
74
|
+
:type => 'text/javascript'
|
75
|
+
|
76
|
+
content_tag :script, options
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
module Capture
|
81
|
+
def content_for(name, content = nil, &block)
|
82
|
+
existing_content_for = instance_variable_get("@content_for_#{name}").to_s
|
83
|
+
new_content_for = existing_content_for + (block_given? ? capture(&block) : content)
|
84
|
+
instance_variable_set("@content_for_#{name}", new_content_for)
|
85
|
+
end
|
86
|
+
|
87
|
+
def capture(*args, &block)
|
88
|
+
# execute the block
|
89
|
+
begin
|
90
|
+
buffer = eval('_erbout', block.binding)
|
91
|
+
rescue
|
92
|
+
buffer = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
if buffer.nil?
|
96
|
+
capture_block(*args, &block).to_s
|
97
|
+
else
|
98
|
+
capture_erb_with_buffer(buffer, *args, &block).to_s
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def capture_block(*args, &block)
|
103
|
+
block.call(*args)
|
104
|
+
end
|
105
|
+
|
106
|
+
def capture_erb(*args, &block)
|
107
|
+
buffer = eval('_erbout', block.binding)
|
108
|
+
capture_erb_with_buffer(buffer, *args, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
def capture_erb_with_buffer(buffer, *args, &block)
|
112
|
+
pos = buffer.length
|
113
|
+
block.call(*args)
|
114
|
+
|
115
|
+
# extract the block
|
116
|
+
data = buffer[pos..-1]
|
117
|
+
|
118
|
+
# replace it in the original with empty string
|
119
|
+
buffer[pos..-1] = ''
|
120
|
+
|
121
|
+
data
|
122
|
+
end
|
123
|
+
|
124
|
+
def concat(string, binding)
|
125
|
+
eval('_erbout', binding) << string
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
include HTML
|
130
|
+
include Capture
|
131
|
+
|
132
|
+
# Simple helper for setting title
|
133
|
+
# Call from a page template with an argument
|
134
|
+
# to set the title; call from the layout with
|
135
|
+
# no argument to get the title
|
136
|
+
def title(value=-1)
|
137
|
+
return @content_for_title if value == -1
|
138
|
+
@content_for_title = value
|
139
|
+
end
|
140
|
+
end
|
data/lib/init.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'boot') if __FILE__ == $0
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class BonesInitializer
|
5
|
+
def self.ensure_file(path, &block)
|
6
|
+
return if File.exist?(path)
|
7
|
+
puts "** Writing #{path}"
|
8
|
+
File.open(path, 'w', &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.ensure_directory(path)
|
12
|
+
return nil if File.directory?(path)
|
13
|
+
puts "** Creating directory #{path}"
|
14
|
+
FileUtils.mkdir_p(path)
|
15
|
+
return true
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.run
|
19
|
+
puts "** Initializing"
|
20
|
+
|
21
|
+
ensure_directory(ROOT / 'public' / 'javascripts')
|
22
|
+
ensure_directory(ROOT / 'public' / 'stylesheets')
|
23
|
+
pages_new = ensure_directory(ROOT / 'pages')
|
24
|
+
ensure_directory(ROOT / 'layouts')
|
25
|
+
ensure_directory(ROOT / 'helpers')
|
26
|
+
|
27
|
+
if pages_new
|
28
|
+
ensure_file(ROOT / 'pages' / 'index.html.erb') do |f|
|
29
|
+
f.write File.read(SYSTEM / 'pages' / 'intro.html.erb')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
ensure_file(ROOT / 'layouts' / 'application.html.erb') do |f|
|
34
|
+
f.write <<-HTML
|
35
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
36
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
37
|
+
<html>
|
38
|
+
<head>
|
39
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
40
|
+
<title>Welcome to bones</title>
|
41
|
+
<%= stylesheet_link_tag 'styles' %>
|
42
|
+
<%= javascript_include_tag %>
|
43
|
+
</head>
|
44
|
+
<body>
|
45
|
+
<h1>Welcome to <strong>bones</strong></h1>
|
46
|
+
<%= @content_for_layout %>
|
47
|
+
</body>
|
48
|
+
</html>
|
49
|
+
HTML
|
50
|
+
end
|
51
|
+
|
52
|
+
ensure_file(ROOT / 'public' / 'stylesheets' / 'styles.css')
|
53
|
+
|
54
|
+
puts "** Adding Rakefile to parent directory"
|
55
|
+
ensure_file(ROOT / 'Rakefile') do |f|
|
56
|
+
f.write File.read(SYSTEM / 'Rakefile')
|
57
|
+
end
|
58
|
+
|
59
|
+
puts <<-HELP if __FILE__ == $0
|
60
|
+
|
61
|
+
All set! Now just run:
|
62
|
+
ruby bones/server.rb
|
63
|
+
|
64
|
+
The app will run on port 3000
|
65
|
+
|
66
|
+
HELP
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
BonesInitializer.run if __FILE__ == $0
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<% layout false %>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
5
|
+
<title>Welcome to bones</title>
|
6
|
+
<%= stylesheet_link_tag 'styles' %>
|
7
|
+
<%= javascript_include_tag %>
|
8
|
+
</head>
|
9
|
+
<h1>Welcome to <strong>bones</strong></h1>
|
10
|
+
<pre>
|
11
|
+
Getting started:
|
12
|
+
|
13
|
+
- Create some files in /pages (i.e. index.html.erb)
|
14
|
+
- Create some directories in /pages if you want as well
|
15
|
+
and drop .html.erb files in them as well
|
16
|
+
- Check out /raw to see all the pages in the system
|
17
|
+
|
18
|
+
Other things you can do:
|
19
|
+
|
20
|
+
- Create partials in /pages (i.e. _footer.html.erb)
|
21
|
+
- Drop anything you want in /public
|
22
|
+
(/stylesheets and /javascripts are created for you)
|
23
|
+
- Customize the layout (/layouts/application.html.erb)
|
24
|
+
- Create your own layout:
|
25
|
+
- Drop the file in /layouts (i.e. /layouts/custom.html.erb)
|
26
|
+
- Use the layout from a page (i.e. <%= layout 'custom' %>)
|
27
|
+
</pre>
|
28
|
+
</html>
|
data/lib/server.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.join(File.dirname(__FILE__), 'boot')
|
3
|
+
require 'init'
|
4
|
+
|
5
|
+
# BonesProxy is simply a proxy class handler
|
6
|
+
# to the actual Bones class - the reason for
|
7
|
+
# this is to allow live changes to Bones
|
8
|
+
# and helpers, etc. The proxy reloads on every
|
9
|
+
# request
|
10
|
+
class BonesProxy
|
11
|
+
# Process incoming request
|
12
|
+
def call(env)
|
13
|
+
reload!
|
14
|
+
Bones.new.call(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Reloads the application
|
18
|
+
def reload!
|
19
|
+
force_load 'Bones' => 'bones.rb'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class BonesServer
|
24
|
+
def self.run
|
25
|
+
app = Rack::Builder.new do
|
26
|
+
use Rack::CommonLogger
|
27
|
+
use Rack::ShowExceptions
|
28
|
+
use Rack::Reloader
|
29
|
+
use Rack::Static, :urls => public_directories, :root => ROOT / 'public'
|
30
|
+
run BonesProxy.new
|
31
|
+
end
|
32
|
+
|
33
|
+
port = ARGV.shift || 3000
|
34
|
+
puts "** Starting bones server on http://0.0.0.0:#{port}"
|
35
|
+
puts "** Public directories: #{public_directories.to_sentence}"
|
36
|
+
Rack::Handler::Mongrel.run app, :Port => port do |server|
|
37
|
+
puts "** Use CTRL-C to stop."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
BonesServer.run if __FILE__ == $0
|
data/lib/tasks/bones.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
desc "Start bones server"
|
2
|
+
task :server do
|
3
|
+
ARGV.shift
|
4
|
+
load File.join(File.dirname(__FILE__), '..', 'server.rb')
|
5
|
+
BonesServer.run
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :cache do
|
9
|
+
desc "Cache page templates for redistribution (non-versioned)"
|
10
|
+
task :simple do
|
11
|
+
ARGV.shift
|
12
|
+
load File.join(File.dirname(__FILE__), '..', 'cache.rb')
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Cache page templatets for redistribution (versioned)"
|
16
|
+
task :versioned do
|
17
|
+
ARGV.shift
|
18
|
+
file = File.join(File.dirname(__FILE__), '..', 'cache.rb')
|
19
|
+
system "ruby #{file} '--versioned'"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
task :clean do
|
24
|
+
# TODO
|
25
|
+
# ARGV.shift
|
26
|
+
# ARGV.unshift '--clean'
|
27
|
+
# load File.join(File.dirname(__FILE__), 'cache.rb')
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scharfie-bones
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Scharf
|
8
|
+
- Ryan Heath
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2008-08-22 00:00:00 -07:00
|
14
|
+
default_executable: bones
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rack
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.3.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
version_requirement:
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.1.0
|
33
|
+
version:
|
34
|
+
description: Simple HTML mockup framework for designers using ERB
|
35
|
+
email: scharfie@gmail.com
|
36
|
+
executables:
|
37
|
+
- bones
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files: []
|
41
|
+
|
42
|
+
files:
|
43
|
+
- README
|
44
|
+
- bin/bones
|
45
|
+
- lib/bones.rb
|
46
|
+
- lib/boot.rb
|
47
|
+
- lib/cache.rb
|
48
|
+
- lib/extensions.rb
|
49
|
+
- lib/helpers
|
50
|
+
- lib/helpers/core_helper.rb
|
51
|
+
- lib/init.rb
|
52
|
+
- lib/pages/directory.html.erb
|
53
|
+
- lib/pages/intro.html.erb
|
54
|
+
- lib/Rakefile
|
55
|
+
- lib/server.rb
|
56
|
+
- lib/tasks/bones.rb
|
57
|
+
- bones.gemspec
|
58
|
+
has_rdoc: false
|
59
|
+
homepage: http://github.com/scharfie/bones
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.2.0
|
81
|
+
signing_key:
|
82
|
+
specification_version: 2
|
83
|
+
summary: Simple HTML mockup framework for designers using ERB
|
84
|
+
test_files: []
|
85
|
+
|