pubba 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +14 -0
- data/.yardopts +2 -0
- data/Gemfile +3 -0
- data/README.md +163 -0
- data/Rakefile +46 -0
- data/lib/sinatra/pubba.rb +28 -0
- data/lib/sinatra/pubba/assets/configuration.rb +25 -0
- data/lib/sinatra/pubba/assets/handler.rb +15 -0
- data/lib/sinatra/pubba/assets/sprockets_handler.rb +34 -0
- data/lib/sinatra/pubba/errors.rb +5 -0
- data/lib/sinatra/pubba/html/helpers.rb +33 -0
- data/lib/sinatra/pubba/locale.rb +18 -0
- data/lib/sinatra/pubba/page.rb +52 -0
- data/lib/sinatra/pubba/site.rb +136 -0
- data/lib/sinatra/pubba/version.rb +5 -0
- data/pubba.gemspec +30 -0
- data/test/helper.rb +73 -0
- data/test/pubba/assets/test_configuration.rb +33 -0
- data/test/pubba/assets/test_handler.rb +16 -0
- data/test/pubba/html/test_helpers.rb +18 -0
- data/test/pubba/test_page.rb +17 -0
- data/test/pubba/test_site.rb +36 -0
- data/test/sinatra/app/assets/javascripts/custom/app.js +3 -0
- data/test/sinatra/app/assets/javascripts/custom/track.js +3 -0
- data/test/sinatra/app/assets/javascripts/third-party/jq.js +3 -0
- data/test/sinatra/app/assets/javascripts/third-party/jqc.js +3 -0
- data/test/sinatra/app/assets/stylesheets/custom/global.css +3 -0
- data/test/sinatra/app/assets/stylesheets/custom/home.css +4 -0
- data/test/sinatra/app/assets/stylesheets/custom/search.css +3 -0
- data/test/sinatra/app/assets/stylesheets/third-party/widget.css +3 -0
- data/test/sinatra/app/i18n/en.yml +15 -0
- data/test/sinatra/config/pubba.yml +20 -0
- data/test/sinatra/public/javascripts/_ +0 -0
- data/test/sinatra/public/stylesheets/_ +0 -0
- metadata +148 -0
data/.gitignore
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
# pubba
|
2
|
+
|
3
|
+
pubba is a Sinatra extension designed to help you manage your site. It uses [Sprockets](https://github.com/sstephenson/sprockets) for packaging assets and [R18n](http://r18n.rubyforge.org/) for internationalization/localization. I use R18n as a central location for default text, the internationalization functionality is a nice bonus in the event the application needs to move in that direction.
|
4
|
+
|
5
|
+
# Note
|
6
|
+
|
7
|
+
This extension is under heavy, heavy development and is subject to massive changes over the next week or so.
|
8
|
+
|
9
|
+
TODO:
|
10
|
+
|
11
|
+
* Support 3rd part script tags in pubba.yml
|
12
|
+
* Add support for media queries on style definitions. This will obviously change the current pubba.yml format.
|
13
|
+
* Remove requirement for placing of scripts/styles in subdirectories. For instance, the convention now is scripts would be in subdirs like javascripts/custom and javscripts/third-party. The only scripts/styles in the root dir are those generated by this extension.
|
14
|
+
* Compress the combined assets
|
15
|
+
* More tests!
|
16
|
+
* Improve documentation!
|
17
|
+
|
18
|
+
# Why?
|
19
|
+
|
20
|
+
There's really two main driving forces behind this extension: audit requirements and code organization.
|
21
|
+
|
22
|
+
If you've ever had to deal with an audit department, you understand some of the strict requirements that can be placed on releases. One of the main themes in audit is providing proof on what was released.
|
23
|
+
|
24
|
+
Any process that involves changing code between environments, even in an automated fashion, is great fodder for the audit machine. This extension makes sure the javascript and css you work with in development is the same as it will be in production.
|
25
|
+
|
26
|
+
This does the require the use of a cache bursting query parameter to be added to the url instead of the digest per asset approach. While the digest approach is much more accurate it complicates using a commit/tag to completely represent the deployment contents.
|
27
|
+
|
28
|
+
As mentioned, code organization is another focus of Pubba. The config file __pubba.yml__ uses the global section to clearly state which assets should be on all pages. In addition, when using R18n, Pubba gives you access through a single page object.
|
29
|
+
|
30
|
+
|
31
|
+
# Settings
|
32
|
+
|
33
|
+
More details on these later, but here are the configuration options:
|
34
|
+
|
35
|
+
**Note: __settings.root__ refers to \<ProjectRoot\>/app/**
|
36
|
+
|
37
|
+
### Location of the config file. REQUIRED
|
38
|
+
set :pubba_config, File.join(settings.root, '..', 'config', 'pubba.yml')
|
39
|
+
|
40
|
+
### Location of the public_folder. REQUIRED
|
41
|
+
set :public_folder, File.join(settings.root, '..', 'public')
|
42
|
+
|
43
|
+
### Location of the asset_folder. REQUIRED
|
44
|
+
set :asset_folder, File.join(settings.root, 'assets')
|
45
|
+
|
46
|
+
### Asset handler. Defaults to [Sprockets](https://github.com/sstephenson/sprockets)
|
47
|
+
Right now there's only support for Sprockets, but leaving the option open for others.
|
48
|
+
set :asset_handler, Sinatra::Pubba::Assets::SprocketsHandler
|
49
|
+
|
50
|
+
### Location of the [R18n](http://r18n.rubyforge.org/) folder. OPTIONAL
|
51
|
+
set :r18n_folder, File.join(settings.root, 'i18n')
|
52
|
+
|
53
|
+
### Locale. Defaults to 'en'
|
54
|
+
set :r18n_locale, 'en'
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
# How?
|
59
|
+
|
60
|
+
First things first, you'll want to install the gem:
|
61
|
+
|
62
|
+
gem install pubba
|
63
|
+
|
64
|
+
Then you'll want to use it in your app like so:
|
65
|
+
|
66
|
+
require 'sinatra/pubba'
|
67
|
+
|
68
|
+
class App < Sinatra::Application
|
69
|
+
# Settings as described above
|
70
|
+
set :asset_folder, File.join(settings.root, 'assets')
|
71
|
+
set :public_folder, File.join(settings.root, '..', 'public')
|
72
|
+
set :r18n_folder, File.join(settings.root, 'i18n')
|
73
|
+
|
74
|
+
set :pubba_config, File.join(settings.root, '..', 'config', 'pubba.yml')
|
75
|
+
|
76
|
+
register Sinatra::Pubba
|
77
|
+
end
|
78
|
+
|
79
|
+
Next up is creating the all important __pubba.yml__ config file:
|
80
|
+
|
81
|
+
global:
|
82
|
+
styles:
|
83
|
+
- "custom/global"
|
84
|
+
head_scripts:
|
85
|
+
- "third-party/jquery-1.7.0.min"
|
86
|
+
body_scripts:
|
87
|
+
- "third-party/jquery.cookie"
|
88
|
+
- "custom/autocomplete"
|
89
|
+
- "custom/application"
|
90
|
+
|
91
|
+
# Home page configuration
|
92
|
+
home:
|
93
|
+
styles:
|
94
|
+
- "custom/home"
|
95
|
+
|
96
|
+
# Search results page configuration
|
97
|
+
search:
|
98
|
+
styles:
|
99
|
+
- "custom/search"
|
100
|
+
|
101
|
+
The config file is referencing the javascripts and stylesheets located in the `asset_folder`.
|
102
|
+
|
103
|
+
If you're using R18n, you will need a translation file, here's a sample en.yml:
|
104
|
+
|
105
|
+
home:
|
106
|
+
title: "Home title"
|
107
|
+
meta_description: "Home meta description"
|
108
|
+
meta_keywords: "Home keywords"
|
109
|
+
welcome_text: "Welcome Home"
|
110
|
+
|
111
|
+
logout_link: "Logout"
|
112
|
+
login_link: "Login"
|
113
|
+
home_link: "Home"
|
114
|
+
account_link: "My Account"
|
115
|
+
|
116
|
+
Take note of the __home__ section in both __pubba.yml__ and __en.yml__. If you have a route in your app that you want to use the __home__ defintions, do this:
|
117
|
+
|
118
|
+
get '/' do
|
119
|
+
@page = Sinatra::Pubba::Site.page('home')
|
120
|
+
slim :"aux/index"
|
121
|
+
end
|
122
|
+
|
123
|
+
The `@page` variable gives you access to the definitions in __en.yml__. In your view you'll be able to use it like so:
|
124
|
+
|
125
|
+
html
|
126
|
+
head
|
127
|
+
title = @page.title
|
128
|
+
body
|
129
|
+
menu
|
130
|
+
a href="/" = @page.home_link
|
131
|
+
|
132
|
+
Notice that `title` is defined under the `home` section, but `home_link` is a top level definition. Pubba makes the effort to correctly resolve the __en.yml__ reference for you. Nice isn't it.
|
133
|
+
|
134
|
+
Now you obviouslly need some helpers to make use of the definitions in __pubba.yml__, and here they are:
|
135
|
+
|
136
|
+
* `page_head_tags`
|
137
|
+
* This helper emits the `link` and `script` tags with the contents defined in __pubba.yml__
|
138
|
+
* `page_body_tags`
|
139
|
+
* This helper emits the `script` tag with the contents defined in __pubba.yml__. You would typically place this just before the `</body>` tag.
|
140
|
+
* `burst(url)`
|
141
|
+
* This helper simply appends a cache bursting parameter named `aid` to the end of the url. In development mode the `aid` value is updated per request. The intent is to help with the particularly aggressive caching Google's Chrome browser likes to implement. In production mode, Pubba requires `ENV[ASSET_ID]` to be set and uses this for the `aid` value. I expect this to be tweaked as I get further into implementation.
|
142
|
+
|
143
|
+
Sample use:
|
144
|
+
|
145
|
+
html
|
146
|
+
head
|
147
|
+
title = @page.title
|
148
|
+
== page_head_tags
|
149
|
+
body
|
150
|
+
menu
|
151
|
+
a href="/" = @page.home_link
|
152
|
+
== page_body_tags
|
153
|
+
|
154
|
+
What you'll see when working with Pubba is that the files in your `asset_folder` are never referenced in your view. Even in development mode! The intent is that development mode is as close to production mode as possible. So, you are working with the same combined asset file you will be deploying.
|
155
|
+
|
156
|
+
# Acknowledgement
|
157
|
+
|
158
|
+
Huge thanks to my company, [Primedia](http://primedia.com) for encouraging open source contributions. This particular extension is obviously very new and hasn't hit a production site yet, but it will. I will post a list here as we migrate our applications from Rails to Sinatra.
|
159
|
+
|
160
|
+
# Contributors
|
161
|
+
|
162
|
+
I highly value contributions and will happily list all those who submit accepted pull requests.
|
163
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler'
|
3
|
+
Bundler::GemHelper.install_tasks
|
4
|
+
rescue Exception => e
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rake/testtask'
|
8
|
+
|
9
|
+
Rake::TestTask.new('test') do |t|
|
10
|
+
t.libs << 'lib' << 'test'
|
11
|
+
t.test_files = Dir.glob('test/**/test_*.rb')
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
task 'test:ci' do |t|
|
16
|
+
Rake::Task[ENV['TASK']].execute
|
17
|
+
end
|
18
|
+
|
19
|
+
begin
|
20
|
+
require 'rcov/rcovtask'
|
21
|
+
Rcov::RcovTask.new do |t|
|
22
|
+
t.libs << 'lib' << 'test'
|
23
|
+
t.test_files = Dir.glob('test/**/test_*.rb')
|
24
|
+
t.verbose = true
|
25
|
+
end
|
26
|
+
rescue LoadError
|
27
|
+
task :rcov do
|
28
|
+
abort "RCov is not available. In order to run rcov, you must: gem install rcov"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
require 'yard'
|
34
|
+
YARD::Rake::YardocTask.new do |t|
|
35
|
+
t.files = %w(lib/**/*.rb)
|
36
|
+
end
|
37
|
+
rescue LoadError
|
38
|
+
task :yard do
|
39
|
+
abort "YARD is not available. In order to run yard, you must: gem install yard"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Generate Documentation"
|
44
|
+
task :doc => :yard
|
45
|
+
|
46
|
+
task :default => 'test'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
require_relative 'pubba/errors'
|
4
|
+
require_relative 'pubba/site'
|
5
|
+
require_relative 'pubba/html/helpers'
|
6
|
+
|
7
|
+
module Sinatra
|
8
|
+
module Pubba
|
9
|
+
def self.registered(app)
|
10
|
+
if app.settings.development? || app.settings.test?
|
11
|
+
Site.configure(app)
|
12
|
+
|
13
|
+
app.before do
|
14
|
+
app.settings.set :asset_id, ->{Time.now.strftime("%N")}
|
15
|
+
end
|
16
|
+
else
|
17
|
+
app.settings.set :asset_id, asset_id
|
18
|
+
end
|
19
|
+
|
20
|
+
app.helpers Sinatra::Pubba::HTML::Helpers
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.asset_id
|
25
|
+
ENV['ASSET_ID'] || raise(ConfigurationError, "Required ENV[ASSET_ID] not defined")
|
26
|
+
end
|
27
|
+
end # Pubba
|
28
|
+
end # Sinatra
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'psych'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module Pubba
|
5
|
+
module Assets
|
6
|
+
class Configuration
|
7
|
+
attr_reader :yaml
|
8
|
+
|
9
|
+
def initialize(config_file)
|
10
|
+
@yaml = Psych.load_file(config_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
def global_config!
|
14
|
+
yaml.delete("global")
|
15
|
+
end
|
16
|
+
|
17
|
+
def process
|
18
|
+
yaml.each do |page, config|
|
19
|
+
yield page, config
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end # Configuration
|
23
|
+
end # Assets
|
24
|
+
end # Pubba
|
25
|
+
end # Sinatra
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'sprockets'
|
2
|
+
require_relative 'handler'
|
3
|
+
|
4
|
+
module Sinatra
|
5
|
+
module Pubba
|
6
|
+
module Assets
|
7
|
+
class SprocketsHandler < Handler
|
8
|
+
def self.find(file)
|
9
|
+
SprocketsHandler.new(sprockets.find_asset(file))
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.asset_paths(*paths)
|
13
|
+
paths.each do |path|
|
14
|
+
sprockets.append_path path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.sprockets
|
19
|
+
@sprockets ||= Sprockets::Environment.new()
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :asset
|
23
|
+
|
24
|
+
def initialize(asset)
|
25
|
+
@asset = asset
|
26
|
+
end
|
27
|
+
|
28
|
+
def save_as(file)
|
29
|
+
asset.write_to(file)
|
30
|
+
end
|
31
|
+
end # SprocketsHandler
|
32
|
+
end # Assets
|
33
|
+
end # Pubba
|
34
|
+
end # Sinatra
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Pubba
|
3
|
+
module HTML
|
4
|
+
module Helpers
|
5
|
+
def page_head_tags
|
6
|
+
tag_content('link', '', { href: burst("/stylesheets/#{@page.name}-styles.css"), rel: "stylesheet", type: "text/css" }) + tag_content('script', '', { src: burst("/javascripts/#{@page.name}-head.js"), type: "text/javascript" })
|
7
|
+
end
|
8
|
+
|
9
|
+
def page_body_tags
|
10
|
+
tag_content('script', '', { src: burst("/javascripts/#{@page.name}-body.js"), type: "text/javascript" })
|
11
|
+
end
|
12
|
+
|
13
|
+
def burst(url)
|
14
|
+
joiner = url.include?("?") ? "&" : "?"
|
15
|
+
"#{url}#{joiner}aid=#{settings.asset_id}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def tag_content(tag, content, attrs={}, self_closing=false)
|
19
|
+
base = "<#{tag}#{tag_attrs(attrs)}"
|
20
|
+
self_closing ? "#{base}/>":"#{base}>#{content}</#{tag}>"
|
21
|
+
end
|
22
|
+
|
23
|
+
def tag_attrs(attrs)
|
24
|
+
return '' if attrs.empty?
|
25
|
+
|
26
|
+
return " " + attrs.collect do |k,v|
|
27
|
+
%|#{k}="#{v}"|
|
28
|
+
end.join(' ')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end # HTML
|
32
|
+
end # Pubba
|
33
|
+
end # Sinatra
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'r18n-desktop'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module Pubba
|
5
|
+
class Locale
|
6
|
+
include R18n::Helpers
|
7
|
+
|
8
|
+
R18n.from_env Site.r18n_folder, Site.r18n_locale
|
9
|
+
|
10
|
+
def get(category, name, *args)
|
11
|
+
res = t.send(category).send(name, *args)
|
12
|
+
res = t.send(name, *args) if R18n::Untranslated === res
|
13
|
+
|
14
|
+
R18n::Untranslated === res ? nil : res
|
15
|
+
end
|
16
|
+
end # Locale
|
17
|
+
end # Pubba
|
18
|
+
end # Sinatra
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Pubba
|
3
|
+
class Page
|
4
|
+
attr_accessor :name
|
5
|
+
attr_reader :assets
|
6
|
+
|
7
|
+
def initialize(name, global_configuration = {})
|
8
|
+
@name = name
|
9
|
+
@assets = {}
|
10
|
+
|
11
|
+
Site.asset_types.keys.each do |asset|
|
12
|
+
@assets[asset] = global_configuration[asset] || []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_asset(name, array)
|
17
|
+
assets[name] += array unless array.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
def assetize
|
21
|
+
Site.asset_types.each{ |key, val| create_asset(key, val) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(meth, *args)
|
25
|
+
if Site.locale && (t = Site.locale.get(name, meth, *args))
|
26
|
+
return t
|
27
|
+
end
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def process_scripts(array)
|
34
|
+
return [] if array.nil? || array.empty?
|
35
|
+
|
36
|
+
array.each{|ele| scripts << ele }
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_asset(asset, dir)
|
40
|
+
type = asset.split('_').first
|
41
|
+
ext = asset.end_with?('styles') ? 'css' : 'js'
|
42
|
+
|
43
|
+
File.open( File.join(dir, "#{name}-#{type}.#{ext}"), 'w') do |f|
|
44
|
+
f.write Site.disclaimer
|
45
|
+
assets[asset].each do |script|
|
46
|
+
f.write "//= require #{script}.#{ext}\n"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end # Page
|
51
|
+
end # Pubba
|
52
|
+
end # Sinatra
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require_relative 'assets/configuration'
|
2
|
+
require_relative 'assets/sprockets_handler'
|
3
|
+
require_relative 'page'
|
4
|
+
|
5
|
+
module Sinatra
|
6
|
+
module Pubba
|
7
|
+
module Site
|
8
|
+
extend self
|
9
|
+
attr_accessor :global_asset_configuration, :asset_handler
|
10
|
+
|
11
|
+
attr_reader :asset_types
|
12
|
+
attr_reader :script_asset_folder, :style_asset_folder
|
13
|
+
attr_reader :script_public_folder, :style_public_folder
|
14
|
+
|
15
|
+
attr_reader :disclaimer
|
16
|
+
|
17
|
+
attr_reader :locale, :r18n_folder, :r18n_locale
|
18
|
+
|
19
|
+
|
20
|
+
def configure(app)
|
21
|
+
settings = app.settings
|
22
|
+
|
23
|
+
validate_settings(settings)
|
24
|
+
|
25
|
+
set_defaults(settings)
|
26
|
+
|
27
|
+
maybe_init_r18n(settings)
|
28
|
+
|
29
|
+
# Load pubba_config
|
30
|
+
asset_configuration = Sinatra::Pubba::Assets::Configuration.new(settings.pubba_config)
|
31
|
+
|
32
|
+
# Set assset handler
|
33
|
+
configure_asset_handler(settings)
|
34
|
+
|
35
|
+
# Grab the global section defined in @pubba_config
|
36
|
+
@global_asset_configuration = asset_configuration.global_config!
|
37
|
+
|
38
|
+
# Process the remaining @pubba_config sections
|
39
|
+
asset_configuration.process do |page, config|
|
40
|
+
Site.add_page(page, config).assetize
|
41
|
+
end
|
42
|
+
|
43
|
+
# Write assets to public_folder
|
44
|
+
compile_assets(app)
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def validate_settings(settings)
|
49
|
+
missing_settings = []
|
50
|
+
unless settings.respond_to? :public_folder
|
51
|
+
missing_settings << ":public_folder has not been set!"
|
52
|
+
end
|
53
|
+
|
54
|
+
unless settings.respond_to? :asset_folder
|
55
|
+
missing_settings << ":asset_folder has not been set!"
|
56
|
+
end
|
57
|
+
|
58
|
+
if missing_settings.length > 0
|
59
|
+
messages = missing_settings.join("\n")
|
60
|
+
raise Pubba::ConfigurationError.new("Missing configuration options:\n#{messages}")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def set_defaults(settings)
|
65
|
+
@script_public_folder = File.join(settings.public_folder, 'javascripts')
|
66
|
+
@style_public_folder = File.join(settings.public_folder, 'stylesheets')
|
67
|
+
@script_asset_folder = File.join(settings.asset_folder, 'javascripts')
|
68
|
+
@style_asset_folder = File.join(settings.asset_folder, 'stylesheets')
|
69
|
+
|
70
|
+
@asset_types = {'styles' => style_asset_folder,
|
71
|
+
'head_scripts' => script_asset_folder,
|
72
|
+
'body_scripts' => script_asset_folder}
|
73
|
+
|
74
|
+
@disclaimer = "// This file is automatically generated from the contents\n// in #{settings.pubba_config}\n//\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
def maybe_init_r18n(settings)
|
78
|
+
return unless settings.respond_to?(:r18n_folder)
|
79
|
+
|
80
|
+
locale = 'en'
|
81
|
+
if settings.respond_to?(:r18n_locale)
|
82
|
+
locale = settings.r18n_locale
|
83
|
+
end
|
84
|
+
|
85
|
+
@r18n_folder = settings.r18n_folder
|
86
|
+
@r18n_locale = locale
|
87
|
+
|
88
|
+
require_relative 'locale'
|
89
|
+
|
90
|
+
@locale = Locale.new
|
91
|
+
end
|
92
|
+
|
93
|
+
def configure_asset_handler(settings)
|
94
|
+
@asset_handler = Sinatra::Pubba::Assets::SprocketsHandler
|
95
|
+
if settings.respond_to?(:asset_handler) && (handler = settings.asset_handler)
|
96
|
+
@asset_handler = handler
|
97
|
+
end
|
98
|
+
@asset_handler.asset_paths style_asset_folder, script_asset_folder
|
99
|
+
end
|
100
|
+
|
101
|
+
def page(name)
|
102
|
+
pages[name]
|
103
|
+
end
|
104
|
+
|
105
|
+
def pages
|
106
|
+
@pages ||= {}
|
107
|
+
end
|
108
|
+
|
109
|
+
def add_page(name, hash)
|
110
|
+
page = Page.new(name, global_asset_configuration)
|
111
|
+
|
112
|
+
asset_types.keys.each do |asset|
|
113
|
+
page.add_asset(asset, hash[asset]) if hash[asset]
|
114
|
+
end
|
115
|
+
|
116
|
+
pages[name] = page
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def compile_assets(app)
|
122
|
+
process_assets(script_asset_folder, script_public_folder)
|
123
|
+
process_assets(style_asset_folder, style_public_folder)
|
124
|
+
end
|
125
|
+
|
126
|
+
def process_assets(from_folder, to_folder)
|
127
|
+
Dir.glob("#{from_folder}/*.*") do |file|
|
128
|
+
asset = asset_handler.find(file)
|
129
|
+
asset.save_as "#{to_folder}/#{File.basename(file)}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
@global_asset_configuration = {}
|
134
|
+
end # Site
|
135
|
+
end # Pubba
|
136
|
+
end # Sinatra
|
data/pubba.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.dirname(__FILE__) + '/lib/sinatra/pubba/version'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'pubba'
|
7
|
+
s.version = Pubba::VERSION
|
8
|
+
s.date = Date.today.to_s
|
9
|
+
s.authors = ['Andrew Stone']
|
10
|
+
s.email = ['andy@stonean.com']
|
11
|
+
s.summary = 'Pubba is a Sinatra extension.'
|
12
|
+
s.description = 'Pubba is a Sinatra extension designed to help you manage your site.'
|
13
|
+
s.homepage = 'http://github.com/stonean/pubba'
|
14
|
+
s.extra_rdoc_files = %w(README.md)
|
15
|
+
s.rdoc_options = %w(--charset=UTF-8)
|
16
|
+
s.rubyforge_project = s.name
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = %w(lib)
|
21
|
+
|
22
|
+
|
23
|
+
s.add_runtime_dependency('sprockets', ['~> 2.1.2'])
|
24
|
+
s.add_runtime_dependency('r18n-desktop', ['~> 0.4.11'])
|
25
|
+
|
26
|
+
s.add_development_dependency('rake', ['>= 0.9.2'])
|
27
|
+
s.add_development_dependency('sinatra', ['>= 1.3.1'])
|
28
|
+
s.add_development_dependency('sinatra-contrib', ['>= 1.3.1'])
|
29
|
+
s.add_development_dependency('yard', ['>= 0'])
|
30
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'minitest/unit'
|
2
|
+
require 'sinatra/test_helpers'
|
3
|
+
|
4
|
+
MiniTest::Unit.autorun
|
5
|
+
|
6
|
+
module R
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def app_folder
|
10
|
+
File.join(File.dirname(__FILE__), 'sinatra', 'app')
|
11
|
+
end
|
12
|
+
|
13
|
+
def asset_folder
|
14
|
+
File.join(app_folder, 'assets')
|
15
|
+
end
|
16
|
+
|
17
|
+
def r18n_folder
|
18
|
+
File.join(app_folder, 'i18n')
|
19
|
+
end
|
20
|
+
|
21
|
+
def public_folder
|
22
|
+
File.join(File.dirname(__FILE__), 'sinatra', 'public')
|
23
|
+
end
|
24
|
+
|
25
|
+
def pubba_config_file
|
26
|
+
File.join(File.dirname(__FILE__), 'sinatra', 'config', 'pubba.yml')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class TestPubba < MiniTest::Unit::TestCase
|
31
|
+
include Sinatra::TestHelpers
|
32
|
+
|
33
|
+
def setup
|
34
|
+
mock_app do
|
35
|
+
require 'sinatra/pubba'
|
36
|
+
|
37
|
+
settings.set :public_folder, R.public_folder
|
38
|
+
settings.set :asset_folder, R.asset_folder
|
39
|
+
settings.set :r18n_folder, R.r18n_folder
|
40
|
+
|
41
|
+
settings.set :pubba_config, R.pubba_config_file
|
42
|
+
|
43
|
+
register Sinatra::Pubba
|
44
|
+
|
45
|
+
get('/home-page-head-tags') do
|
46
|
+
@page = Sinatra::Pubba::Site.page('home');
|
47
|
+
page_head_tags
|
48
|
+
end
|
49
|
+
|
50
|
+
get('/home-page-body-tags') do
|
51
|
+
@page = Sinatra::Pubba::Site.page('home');
|
52
|
+
page_body_tags
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def teardown
|
58
|
+
[R.asset_folder, R.public_folder].each do |root_folder|
|
59
|
+
Dir.glob(File.join(root_folder, 'javascripts', '*.js')) do |f|
|
60
|
+
File.delete(f) if File.exist?(f)
|
61
|
+
end
|
62
|
+
|
63
|
+
Dir.glob(File.join(root_folder, 'stylesheets', '*.css')) do |f|
|
64
|
+
File.delete(f) if File.exist?(f)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def empty_hash
|
70
|
+
{}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestPubbaAssetsConfiguration < TestPubba
|
4
|
+
def setup
|
5
|
+
@config = Sinatra::Pubba::Assets::Configuration.new(R.pubba_config_file)
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_yaml_is_initialized
|
9
|
+
hsh = {"global"=>{"styles"=>["custom/global"], "head_scripts"=>["third-party/jq"], "body_scripts"=>["third-party/jqc", "custom/app"]}, "home"=>{"styles"=>["custom/home"]}, "search"=>{"styles"=>["custom/search", "third-party/widget"]}}
|
10
|
+
assert_equal hsh, @config.yaml
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_global_config
|
14
|
+
hsh = {"styles"=>["custom/global"], "head_scripts"=>["third-party/jq"], "body_scripts"=>["third-party/jqc", "custom/app"]}
|
15
|
+
assert_equal hsh, @config.global_config!
|
16
|
+
|
17
|
+
assert_nil @config.yaml["global"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_process
|
21
|
+
sections = ["home", "search"]
|
22
|
+
|
23
|
+
@config.global_config!
|
24
|
+
|
25
|
+
@config.process do |page, config|
|
26
|
+
assert sections.include?(page), "Page :#{page} not expected"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def teardown
|
31
|
+
@config = nil
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestHandler < TestPubba
|
4
|
+
def test_asset
|
5
|
+
assert_raises NotImplementedError do
|
6
|
+
Sinatra::Pubba::Assets::Handler.asset('')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_save_as
|
11
|
+
handler = Sinatra::Pubba::Assets::Handler.new
|
12
|
+
assert_raises NotImplementedError do
|
13
|
+
handler.save_as('')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'sinatra/pubba/html/helpers'
|
3
|
+
|
4
|
+
class TestPubbaHTMLHelper < TestPubba
|
5
|
+
include Sinatra::Pubba::HTML::Helpers
|
6
|
+
|
7
|
+
def test_home_page_head_tags
|
8
|
+
res = get('/home-page-head-tags').body.gsub /\d/,'1'
|
9
|
+
str = %|<link href="/stylesheets/home-styles.css?aid=111111111" rel="stylesheet" type="text/css"></link><script src="/javascripts/home-head.js?aid=111111111" type="text/javascript"></script>|
|
10
|
+
assert_equal str, res
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_home_page_body_tags
|
14
|
+
res = get('/home-page-body-tags').body.gsub /\d/,'1'
|
15
|
+
str = %|<script src="/javascripts/home-body.js?aid=111111111" type="text/javascript"></script>|
|
16
|
+
assert_equal str, res
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestPubbaPage < TestPubba
|
4
|
+
def test_home_r18n
|
5
|
+
page = Sinatra::Pubba::Site.page('home')
|
6
|
+
|
7
|
+
assert_equal 'Home title', page.title
|
8
|
+
assert_equal 'Logout', page.logout_link
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_search_r18n
|
12
|
+
page = Sinatra::Pubba::Site.page('search')
|
13
|
+
|
14
|
+
assert_equal 'Search title', page.title
|
15
|
+
assert_equal 'Logout', page.logout_link
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestPubbaSite < TestPubba
|
4
|
+
def test_global_asset_configuration_initialization
|
5
|
+
hsh = {"styles"=>["custom/global"], "head_scripts"=>["third-party/jq"], "body_scripts"=>["third-party/jqc", "custom/app"]}
|
6
|
+
assert_equal hsh, Sinatra::Pubba::Site.global_asset_configuration
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_asset_handler_initialization
|
10
|
+
assert_equal Sinatra::Pubba::Assets::SprocketsHandler, Sinatra::Pubba::Site.asset_handler
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_script_public_folder_initialization
|
14
|
+
assert_equal "#{R.public_folder}/javascripts", Sinatra::Pubba::Site.script_public_folder
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_style_public_folder_initialization
|
18
|
+
assert_equal "#{R.public_folder}/stylesheets", Sinatra::Pubba::Site.style_public_folder
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_script_asset_folder_initialization
|
22
|
+
assert_equal "#{R.asset_folder}/javascripts", Sinatra::Pubba::Site.script_asset_folder
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_style_asset_folder_initialization
|
26
|
+
assert_equal "#{R.asset_folder}/stylesheets", Sinatra::Pubba::Site.style_asset_folder
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_asset_types_initialization
|
30
|
+
asset_types = Sinatra::Pubba::Site.asset_types
|
31
|
+
assert_equal Sinatra::Pubba::Site.style_asset_folder, asset_types.delete('styles')
|
32
|
+
assert_equal Sinatra::Pubba::Site.script_asset_folder, asset_types.delete('head_scripts')
|
33
|
+
assert_equal Sinatra::Pubba::Site.script_asset_folder, asset_types.delete('body_scripts')
|
34
|
+
assert asset_types.empty?
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
home:
|
2
|
+
title: "Home title"
|
3
|
+
meta_description: "Home meta description"
|
4
|
+
meta_keywords: "Home keywords"
|
5
|
+
welcome_text: "Welcome Home"
|
6
|
+
|
7
|
+
search:
|
8
|
+
title: "Search title"
|
9
|
+
meta_description: "Search meta description"
|
10
|
+
meta_keywords: "Search meta keywords"
|
11
|
+
|
12
|
+
logout_link: "Logout"
|
13
|
+
login_link: "Login"
|
14
|
+
home_link: "Home"
|
15
|
+
account_link: "My Account"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Global configuration. Settings here will be applied to all pages.
|
2
|
+
global:
|
3
|
+
styles:
|
4
|
+
- "custom/global"
|
5
|
+
head_scripts:
|
6
|
+
- "third-party/jq"
|
7
|
+
body_scripts:
|
8
|
+
- "third-party/jqc"
|
9
|
+
- "custom/app"
|
10
|
+
|
11
|
+
# Home page configuration
|
12
|
+
home:
|
13
|
+
styles:
|
14
|
+
- "custom/home"
|
15
|
+
|
16
|
+
# Search page configuration
|
17
|
+
search:
|
18
|
+
styles:
|
19
|
+
- "custom/search"
|
20
|
+
- "third-party/widget"
|
File without changes
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pubba
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Andrew Stone
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sprockets
|
16
|
+
requirement: &2151906900 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.1.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2151906900
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: r18n-desktop
|
27
|
+
requirement: &2151906320 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.4.11
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2151906320
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &2151905780 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.2
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2151905780
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sinatra
|
49
|
+
requirement: &2151905080 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.1
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2151905080
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: sinatra-contrib
|
60
|
+
requirement: &2151904480 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.3.1
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2151904480
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yard
|
71
|
+
requirement: &2151903920 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2151903920
|
80
|
+
description: Pubba is a Sinatra extension designed to help you manage your site.
|
81
|
+
email:
|
82
|
+
- andy@stonean.com
|
83
|
+
executables: []
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files:
|
86
|
+
- README.md
|
87
|
+
files:
|
88
|
+
- .gitignore
|
89
|
+
- .yardopts
|
90
|
+
- Gemfile
|
91
|
+
- README.md
|
92
|
+
- Rakefile
|
93
|
+
- lib/sinatra/pubba.rb
|
94
|
+
- lib/sinatra/pubba/assets/configuration.rb
|
95
|
+
- lib/sinatra/pubba/assets/handler.rb
|
96
|
+
- lib/sinatra/pubba/assets/sprockets_handler.rb
|
97
|
+
- lib/sinatra/pubba/errors.rb
|
98
|
+
- lib/sinatra/pubba/html/helpers.rb
|
99
|
+
- lib/sinatra/pubba/locale.rb
|
100
|
+
- lib/sinatra/pubba/page.rb
|
101
|
+
- lib/sinatra/pubba/site.rb
|
102
|
+
- lib/sinatra/pubba/version.rb
|
103
|
+
- pubba.gemspec
|
104
|
+
- test/helper.rb
|
105
|
+
- test/pubba/assets/test_configuration.rb
|
106
|
+
- test/pubba/assets/test_handler.rb
|
107
|
+
- test/pubba/html/test_helpers.rb
|
108
|
+
- test/pubba/test_page.rb
|
109
|
+
- test/pubba/test_site.rb
|
110
|
+
- test/sinatra/app/assets/javascripts/custom/app.js
|
111
|
+
- test/sinatra/app/assets/javascripts/custom/track.js
|
112
|
+
- test/sinatra/app/assets/javascripts/third-party/jq.js
|
113
|
+
- test/sinatra/app/assets/javascripts/third-party/jqc.js
|
114
|
+
- test/sinatra/app/assets/stylesheets/custom/global.css
|
115
|
+
- test/sinatra/app/assets/stylesheets/custom/home.css
|
116
|
+
- test/sinatra/app/assets/stylesheets/custom/search.css
|
117
|
+
- test/sinatra/app/assets/stylesheets/third-party/widget.css
|
118
|
+
- test/sinatra/app/i18n/en.yml
|
119
|
+
- test/sinatra/config/pubba.yml
|
120
|
+
- test/sinatra/public/javascripts/_
|
121
|
+
- test/sinatra/public/stylesheets/_
|
122
|
+
homepage: http://github.com/stonean/pubba
|
123
|
+
licenses: []
|
124
|
+
post_install_message:
|
125
|
+
rdoc_options:
|
126
|
+
- --charset=UTF-8
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project: pubba
|
143
|
+
rubygems_version: 1.8.10
|
144
|
+
signing_key:
|
145
|
+
specification_version: 3
|
146
|
+
summary: Pubba is a Sinatra extension.
|
147
|
+
test_files: []
|
148
|
+
has_rdoc:
|