soxer 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/soxer/main.rb +241 -0
- data/lib/soxer/views/atom.haml +32 -0
- data/lib/soxer/views/disqus.haml +26 -0
- data/lib/soxer/views/google_ads.haml +6 -0
- data/lib/soxer/views/google_analytics.haml +27 -0
- data/lib/soxer/views/recaptcha.haml +19 -0
- data/lib/soxer/views/sitemap.haml +10 -0
- data/lib/soxer.rb +7 -0
- data/soxer.gemspec +42 -0
- metadata +116 -0
data/lib/soxer/main.rb
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'yaml'
|
3
|
+
require 'haml'
|
4
|
+
require 'uuid'
|
5
|
+
|
6
|
+
|
7
|
+
module Sinatra
|
8
|
+
|
9
|
+
#== Soxer, the web publishing tool.
|
10
|
+
#
|
11
|
+
# Soxer is a Sinatra module that adds additional methods to sinatra routes.
|
12
|
+
# These methods allow for route-to-yaml-file mapping in order to serve a set
|
13
|
+
# files from disk with minimal effort. By clever use of views and/or
|
14
|
+
# templating Soxer makes for a simple and effective web site creation tool.
|
15
|
+
# You can get more information about Soxer, including the latest version at
|
16
|
+
# http://soxer.mutsu.org
|
17
|
+
#
|
18
|
+
# Author: Toni Anzlovar (toni[at]formalibre.si)
|
19
|
+
# Copyright: Copyright (c) 1010 Toni Anzlovar, www.formalibre.si
|
20
|
+
# License: Distributed under the GPL licence. http://www.gnu.org/licenses/gpl.html
|
21
|
+
module Soxer
|
22
|
+
|
23
|
+
class Filereader
|
24
|
+
attr_accessor :filename
|
25
|
+
|
26
|
+
def settings
|
27
|
+
@s = Sinatra::Application
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_content
|
31
|
+
self.settings
|
32
|
+
out = YAML.load_file( @filename )
|
33
|
+
add_date unless out['date']
|
34
|
+
add_id unless out['uuid']
|
35
|
+
out['url'] = @filename.gsub(/#{@s.root}\/#{@s.origin}(.+)\.yaml$/, "\\1" ).gsub(/(.+)\/index$/, "\\1" )
|
36
|
+
out['mtime'] = File.mtime( @filename )
|
37
|
+
out
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def add_id
|
43
|
+
mtime = File.mtime( @filename )
|
44
|
+
File.open( @filename, 'r+' ) do |f|
|
45
|
+
out = "uuid: #{UUID.new.generate}\n"
|
46
|
+
out << f.read; f.pos = 0
|
47
|
+
f << out
|
48
|
+
end
|
49
|
+
File.utime( 0, mtime, @filename )
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_date
|
53
|
+
mtime = File.mtime( @filename )
|
54
|
+
File.open( @filename, 'r+' ) do |f|
|
55
|
+
out = "date: #{mtime.xmlschema}\n"
|
56
|
+
out << f.read; f.pos = 0
|
57
|
+
f << out
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Urlreader
|
63
|
+
attr_accessor :url
|
64
|
+
|
65
|
+
def settings
|
66
|
+
@s = Sinatra::Application
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_content
|
70
|
+
self.settings
|
71
|
+
fn = case true
|
72
|
+
when File.exist?( f = File.join( @s.root, @s.origin, @url+'.yaml' ) ) then f
|
73
|
+
when File.exist?( f = File.join( @s.root, @s.origin, @url+'/index.yaml' ) ) then f
|
74
|
+
else throw :halt, [404, "Document not found"]
|
75
|
+
end
|
76
|
+
out = Filereader.new
|
77
|
+
out.filename = fn
|
78
|
+
out.get_content
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# === The "get_page", the document reading function
|
83
|
+
#
|
84
|
+
# Read the document in yaml format (with .yaml) ending directly mapped from
|
85
|
+
# the given parameter. Sinatra's *settings.route* and Soxers
|
86
|
+
# *settings.origin* are prefixed to the path in order to get an absolute
|
87
|
+
# filename. If the filename cannot be found, a directory by that name and
|
88
|
+
# an index file within are probed and read.
|
89
|
+
#
|
90
|
+
# If no parameter is given, the entire route is taken as the argument.
|
91
|
+
def get_page url=params[:splat][0]
|
92
|
+
out = Urlreader.new
|
93
|
+
out.url = url
|
94
|
+
out.get_content
|
95
|
+
end
|
96
|
+
|
97
|
+
#=== The "get_list" the document listing function
|
98
|
+
#
|
99
|
+
# The get_list function is the aggregator function. It reads all available
|
100
|
+
# yaml files (that map to urls directly) and outputs them according to the
|
101
|
+
# arguments you send it. Get_list only accepts 1 argument and a block.
|
102
|
+
#
|
103
|
+
#==== sort='desc'
|
104
|
+
# Direction of output. 'desc' (descending) or 'asc' (ascending)The default
|
105
|
+
# is 'desc'. If :sort conatins anything else, the output is unsorted.
|
106
|
+
#
|
107
|
+
#==== &block
|
108
|
+
# Block is a callback. Every file (in hash form) is passed to block and
|
109
|
+
# the block acts as the filter. :sort only takes the result and sorts it
|
110
|
+
# according to the first key/value pair, so hash order IS signifficant.
|
111
|
+
def get_list sort='desc', &block
|
112
|
+
pattern = File.join( settings.root, settings.origin, "**", "*.yaml" )
|
113
|
+
output = Dir.glob(pattern).map! do |f|
|
114
|
+
file = Filereader.new
|
115
|
+
file.filename = f
|
116
|
+
if block_given?
|
117
|
+
f = block.call file.get_content
|
118
|
+
end
|
119
|
+
end.compact
|
120
|
+
case sort
|
121
|
+
when 'desc' then output.sort!{|b,a| a.to_a[0] <=> b.to_a[0] }
|
122
|
+
when 'asc' then output.sort!{|a,b| a.to_a[0] <=> b.to_a[0] }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
#=== The "sitemap" the sitemap generator
|
127
|
+
#
|
128
|
+
# This funnction accepts no arguments. It simply renders a sitemap file
|
129
|
+
# with all available urls from the site
|
130
|
+
def sitemap
|
131
|
+
template = File.read File.join( File.dirname(__FILE__), 'views', 'sitemap.haml' )
|
132
|
+
out = '<?xml version="1.0" encoding="UTF-8"?>'+"\n"
|
133
|
+
out << haml( template, :layout => false )
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
#=== The "atom" the atom feed generator
|
138
|
+
#
|
139
|
+
# This method accepts an author (which is the global feed's author)
|
140
|
+
# This is a required option, as the feed is only valid if it has at least
|
141
|
+
# the global author. If individual articles have a yaml field "author",
|
142
|
+
# the individual article's author is used for that article. In both cases,
|
143
|
+
# author is a hash consisting of values 'name', 'email', 'url', of which
|
144
|
+
# at least the 'name' should always be present.
|
145
|
+
#
|
146
|
+
#==== autor
|
147
|
+
# Hash of values as required by the Atom standard:
|
148
|
+
# 'name', 'email' and 'url'. Only name is reuired.
|
149
|
+
#
|
150
|
+
#==== &block
|
151
|
+
# Block is a callback. Every file (in hash form) is passed to block and
|
152
|
+
# the block acts as the filter. That way only pages which are returned by
|
153
|
+
# block are included in the feed
|
154
|
+
def atom author=author, &block
|
155
|
+
template = File.read File.join( File.dirname(__FILE__), 'views', 'atom.haml' )
|
156
|
+
pattern = File.join( settings.root, settings.origin, "**", "*.yaml" )
|
157
|
+
output = Dir.glob(pattern).map! do |f|
|
158
|
+
file = Filereader.new
|
159
|
+
file.filename = f
|
160
|
+
if block_given?
|
161
|
+
block.call file.get_content
|
162
|
+
end
|
163
|
+
end.compact!.sort!{|b,a| a.to_a[0] <=> b.to_a[0] }
|
164
|
+
out = '<?xml version="1.0" encoding="UTF-8"?>'+"\n"
|
165
|
+
out << haml( template, :layout => false, :locals => { :page=>get_page, :feed=>output, :author=>author } )
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
def google_ads options={}
|
170
|
+
template = File.read File.join( File.dirname(__FILE__), 'views', 'google_ads.haml' )
|
171
|
+
pattern = File.join( settings.root, settings.origin, "**", "*.yaml" )
|
172
|
+
haml( template, options.merge!( :layout => false ) )
|
173
|
+
end
|
174
|
+
|
175
|
+
def disqus options={}
|
176
|
+
template = File.read File.join( File.dirname(__FILE__), 'views', 'disqus.haml' )
|
177
|
+
haml( template, options.merge!( :layout => false ) )
|
178
|
+
end
|
179
|
+
|
180
|
+
def google_analytics options={}
|
181
|
+
template = File.read File.join( File.dirname(__FILE__), 'views', 'google_analytics.haml' )
|
182
|
+
haml( template, options.merge!( :layout => false ) )
|
183
|
+
end
|
184
|
+
|
185
|
+
def recaptcha options={}
|
186
|
+
template = File.read File.join( File.dirname(__FILE__), 'views', 'recaptcha.haml' )
|
187
|
+
haml( template, options.merge!( :layout => false ) )
|
188
|
+
end
|
189
|
+
|
190
|
+
#=== "partial" rails like partial generator
|
191
|
+
#
|
192
|
+
# This funnction accepts a string and matches it to a haml layout (with a
|
193
|
+
# underscore prepended) Sinatra's layouts directory.
|
194
|
+
#
|
195
|
+
#==== snippet
|
196
|
+
# A string that maps to a haml view in the views directory
|
197
|
+
# "partial :example, :layout => false" would map to a views/_example.haml
|
198
|
+
#
|
199
|
+
#==== options={}
|
200
|
+
# Any options you pass to this partial ger merged and sent to haml as
|
201
|
+
# sinatra's haml options (this is usefull for passing sinatra's :layout,
|
202
|
+
# :locals and other variables)
|
203
|
+
def partial(snippet, options={})
|
204
|
+
haml ('_'+snippet).to_sym, options.merge!(:layout => false)
|
205
|
+
end
|
206
|
+
|
207
|
+
#=== "link_to" rails like link_to generator
|
208
|
+
#
|
209
|
+
# This funnction accepts a 1 or 2 strings.
|
210
|
+
#
|
211
|
+
#==== text
|
212
|
+
# A string that becomes the link text. If there is no second parameter,
|
213
|
+
# link_to converts the string into a local url by replacing all spaces with
|
214
|
+
# an underscore and downcasing the string.
|
215
|
+
#
|
216
|
+
#==== url
|
217
|
+
# This string is used for 'href' in a link
|
218
|
+
def link_to(text, url="/#{text.downcase.gsub(/\s/,'_')}")
|
219
|
+
url.gsub!(/^\//, '') if url =~ /.+:\/\//
|
220
|
+
"<a href=\"#{url}\"> #{text}</a>"
|
221
|
+
end
|
222
|
+
|
223
|
+
# A simple string obuscator.
|
224
|
+
# Useful for hiding emails and such
|
225
|
+
#=== "obfuscate" simple string obuscator.
|
226
|
+
#
|
227
|
+
# This funnction accepts a 1 or 2 strings.
|
228
|
+
#
|
229
|
+
#==== str=nil
|
230
|
+
# Obfuscates a string replacing characters with html entities.
|
231
|
+
# Useful for hiding emails and such
|
232
|
+
def obfuscate(str=nil)
|
233
|
+
out = []
|
234
|
+
str.each_byte {|c| out << "&##{c};" }
|
235
|
+
out.join
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
helpers Soxer
|
241
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
%feed(xmlns="http://www.w3.org/2005/Atom")
|
2
|
+
%title= page['title']
|
3
|
+
%link{:href=>request.url.split(request.fullpath)[0].gsub(/:\d+/, '')}
|
4
|
+
%link(rel="self"){:href=>request.url.gsub(/:\d+/, '')}
|
5
|
+
%id= "urn:uuid:"+page['uuid']
|
6
|
+
%updated= feed[0]['mtime'].xmlschema
|
7
|
+
%author
|
8
|
+
%name= author['name']
|
9
|
+
- if author['email'] and author['email'].length > 0
|
10
|
+
%email= author['email']
|
11
|
+
- if author['uri'] and author['uri'].length > 0
|
12
|
+
%uri= author['uri']
|
13
|
+
|
14
|
+
-feed.each do |f|
|
15
|
+
%entry
|
16
|
+
%title= f['title']
|
17
|
+
%link{:href=>f['url']}
|
18
|
+
%id= "urn:uuid:"+f['uuid']
|
19
|
+
%updated= f['mtime'].xmlschema
|
20
|
+
%published= f['date'].xmlschema
|
21
|
+
- if f['summary'] and f['summary'].length > 0
|
22
|
+
- s = haml f['summary'], :layout=>false
|
23
|
+
%summary= s.gsub(%r{</?[^>]+?>}, '')
|
24
|
+
- if f['author']
|
25
|
+
%author
|
26
|
+
- if f['author']['name'] and f['author']['name'].length > 0
|
27
|
+
%name= f['author']['name']
|
28
|
+
- if f['author']['email'] and f['author']['email'].length > 0
|
29
|
+
%email= f['author']['email']
|
30
|
+
- if f['author']['uri'] and f['author']['uri'].length > 0
|
31
|
+
%uri= f['author']['uri']
|
32
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
- if defined?(account)
|
2
|
+
#disqus_thread
|
3
|
+
:javascript
|
4
|
+
(function() {
|
5
|
+
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
6
|
+
dsq.src = 'http://#{account}.disqus.com/embed.js';
|
7
|
+
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
8
|
+
})();
|
9
|
+
%noscript Please enable JavaScript to view the #{link_to 'comments powered by Disqus', 'http://disqus.com/?ref_noscript=#{account}'}.
|
10
|
+
%a.dsq-brlink(href="http://disqus.com")
|
11
|
+
blog comments powered by
|
12
|
+
%span.logo-disqus Disqus
|
13
|
+
|
14
|
+
- if !defined?(account)
|
15
|
+
:javascript
|
16
|
+
(function() {
|
17
|
+
var links = document.getElementsByTagName('a');
|
18
|
+
var query = '?';
|
19
|
+
for(var i = 0; i < links.length; i++) {
|
20
|
+
if(links[i].href.indexOf('#disqus_thread') >= 0) {
|
21
|
+
query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&';
|
22
|
+
}
|
23
|
+
}
|
24
|
+
document.write('<script charset="utf-8" type="text/javascript" src="http://disqus.com/forums/soxer/get_num_replies.js' + query + '"></' + 'script>');
|
25
|
+
})();
|
26
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
-#-----------------------------------------------------------------------------
|
2
|
+
-# OLD
|
3
|
+
-#-----------------------------------------------------------------------------
|
4
|
+
-#:javascript
|
5
|
+
-# var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
6
|
+
-# document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
7
|
+
-#
|
8
|
+
-#:javascript
|
9
|
+
-# try {
|
10
|
+
-# var pageTracker = _gat._getTracker("#{tracker}");
|
11
|
+
-# pageTracker._trackPageview();
|
12
|
+
-# } catch(err) {}
|
13
|
+
-#-----------------------------------------------------------------------------
|
14
|
+
|
15
|
+
-#-----------------------------------------------------------------------------
|
16
|
+
-# New, asynchronus
|
17
|
+
-#-----------------------------------------------------------------------------
|
18
|
+
:javascript
|
19
|
+
var _gaq = _gaq || [];
|
20
|
+
_gaq.push(['_setAccount', '#{tracker}']);
|
21
|
+
_gaq.push(['_trackPageview']);
|
22
|
+
(function() {
|
23
|
+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
24
|
+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
25
|
+
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
26
|
+
})();
|
27
|
+
-#-----------------------------------------------------------------------------
|
@@ -0,0 +1,19 @@
|
|
1
|
+
:ruby
|
2
|
+
width ||= 500;
|
3
|
+
height ||= 300;
|
4
|
+
theme ||= 'white'
|
5
|
+
lang ||= 'en'
|
6
|
+
|
7
|
+
%script(type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js")
|
8
|
+
:javascript
|
9
|
+
Recaptcha.create("#{key}", "recaptcha", {
|
10
|
+
theme: "#{theme}",
|
11
|
+
callback: Recaptcha.focus_response_field }
|
12
|
+
);
|
13
|
+
%noscript
|
14
|
+
%iframe(src="http://www.google.com/recaptcha/api/noscript?k=#{key}" height="#{height}" width="#{width}" frameborder="0")
|
15
|
+
%br
|
16
|
+
%textarea(name="recaptcha_challenge_field" rows="3" cols="40")
|
17
|
+
%input(type="hidden" name="recaptcha_response_field" value="manual_challenge")
|
18
|
+
|
19
|
+
#recaptcha
|
@@ -0,0 +1,10 @@
|
|
1
|
+
:ruby
|
2
|
+
site = env['HTTP_X_FORWARDED_HOST'] ? env['HTTP_X_FORWARDED_HOST'] : env['HTTP_HOST']
|
3
|
+
|
4
|
+
%urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
|
5
|
+
- pattern = File.join( settings.root, settings.origin, "**", "*.yaml" )
|
6
|
+
- Dir.glob(pattern).each do |file|
|
7
|
+
%url
|
8
|
+
%loc= "http://#{site}"+file.gsub(/#{settings.root}\/#{settings.origin}(.+)\.yaml$/, "\\1" ).gsub(/(.+)\/index$/, "\\1" )
|
9
|
+
%lastmod= File.mtime( file ).xmlschema
|
10
|
+
|
data/lib/soxer.rb
ADDED
data/soxer.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
3
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
|
+
s.rubygems_version = '1.3.7'
|
5
|
+
|
6
|
+
s.name = 'soxer'
|
7
|
+
s.version = '0.9.0'
|
8
|
+
s.date = '2010-10-25'
|
9
|
+
s.rubyforge_project = 'soxer'
|
10
|
+
|
11
|
+
s.summary = "Dynamic web site engine"
|
12
|
+
s.description = "Soxer is a file based dynamic web creation tool for Sinatra."
|
13
|
+
|
14
|
+
s.authors = ["Toni Anzlovar"]
|
15
|
+
s.email = 'toni@formalibre.si'
|
16
|
+
s.homepage = 'http://soxer.mutsu.org'
|
17
|
+
|
18
|
+
s.require_paths = %w[lib]
|
19
|
+
|
20
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
21
|
+
# s.extra_rdoc_files = %w[README.md LICENSE]
|
22
|
+
|
23
|
+
s.add_dependency('sinatra', "~> 1")
|
24
|
+
s.add_dependency('haml', "~> 3")
|
25
|
+
s.add_dependency('uuid', "~> 2")
|
26
|
+
|
27
|
+
# = MANIFEST =
|
28
|
+
s.files = %w[
|
29
|
+
soxer.gemspec
|
30
|
+
lib/soxer.rb
|
31
|
+
lib/soxer/main.rb
|
32
|
+
lib/soxer/views/sitemap.haml
|
33
|
+
lib/soxer/views/recaptcha.haml
|
34
|
+
lib/soxer/views/google_analytics.haml
|
35
|
+
lib/soxer/views/google_ads.haml
|
36
|
+
lib/soxer/views/disqus.haml
|
37
|
+
lib/soxer/views/atom.haml
|
38
|
+
]
|
39
|
+
# = MANIFEST =
|
40
|
+
|
41
|
+
s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: soxer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 59
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 9
|
9
|
+
- 0
|
10
|
+
version: 0.9.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Toni Anzlovar
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-25 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: sinatra
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 1
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
version: "1"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: haml
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 5
|
44
|
+
segments:
|
45
|
+
- 3
|
46
|
+
version: "3"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: uuid
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ~>
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 7
|
58
|
+
segments:
|
59
|
+
- 2
|
60
|
+
version: "2"
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
description: Soxer is a file based dynamic web creation tool for Sinatra.
|
64
|
+
email: toni@formalibre.si
|
65
|
+
executables: []
|
66
|
+
|
67
|
+
extensions: []
|
68
|
+
|
69
|
+
extra_rdoc_files: []
|
70
|
+
|
71
|
+
files:
|
72
|
+
- soxer.gemspec
|
73
|
+
- lib/soxer.rb
|
74
|
+
- lib/soxer/main.rb
|
75
|
+
- lib/soxer/views/sitemap.haml
|
76
|
+
- lib/soxer/views/recaptcha.haml
|
77
|
+
- lib/soxer/views/google_analytics.haml
|
78
|
+
- lib/soxer/views/google_ads.haml
|
79
|
+
- lib/soxer/views/disqus.haml
|
80
|
+
- lib/soxer/views/atom.haml
|
81
|
+
has_rdoc: true
|
82
|
+
homepage: http://soxer.mutsu.org
|
83
|
+
licenses: []
|
84
|
+
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options:
|
87
|
+
- --charset=UTF-8
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 3
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project: soxer
|
111
|
+
rubygems_version: 1.3.7
|
112
|
+
signing_key:
|
113
|
+
specification_version: 2
|
114
|
+
summary: Dynamic web site engine
|
115
|
+
test_files: []
|
116
|
+
|