bbrowning-deltacloud-core 0.0.4-java
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/COPYING +176 -0
- data/Rakefile +99 -0
- data/bin/deltacloudd +120 -0
- data/config.ru +5 -0
- data/deltacloud.rb +18 -0
- data/lib/deltacloud/base_driver/base_driver.rb +229 -0
- data/lib/deltacloud/base_driver/features.rb +166 -0
- data/lib/deltacloud/base_driver/mock_driver.rb +40 -0
- data/lib/deltacloud/base_driver.rb +20 -0
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +410 -0
- data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +170 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +50 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +332 -0
- data/lib/deltacloud/drivers/gogrid/test.rb +13 -0
- data/lib/deltacloud/drivers/mock/data/images/img1.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/images/img2.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/images/img3.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +16 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +9 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +9 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap1.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap2.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap3.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +6 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +6 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +6 -0
- data/lib/deltacloud/drivers/mock/mock_driver.rb +277 -0
- data/lib/deltacloud/drivers/opennebula/cloud_client.rb +116 -0
- data/lib/deltacloud/drivers/opennebula/occi_client.rb +204 -0
- data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +241 -0
- data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +130 -0
- data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +182 -0
- data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +255 -0
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb +85 -0
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +166 -0
- data/lib/deltacloud/drivers/terremark/terremark_driver.rb +286 -0
- data/lib/deltacloud/hardware_profile.rb +153 -0
- data/lib/deltacloud/helpers/application_helper.rb +115 -0
- data/lib/deltacloud/helpers/conversion_helper.rb +39 -0
- data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
- data/lib/deltacloud/helpers.rb +5 -0
- data/lib/deltacloud/method_serializer.rb +85 -0
- data/lib/deltacloud/models/base_model.rb +59 -0
- data/lib/deltacloud/models/image.rb +27 -0
- data/lib/deltacloud/models/instance.rb +38 -0
- data/lib/deltacloud/models/instance_profile.rb +48 -0
- data/lib/deltacloud/models/key.rb +35 -0
- data/lib/deltacloud/models/realm.rb +26 -0
- data/lib/deltacloud/models/storage_snapshot.rb +27 -0
- data/lib/deltacloud/models/storage_volume.rb +28 -0
- data/lib/deltacloud/state_machine.rb +84 -0
- data/lib/deltacloud/validation.rb +70 -0
- data/lib/drivers.rb +50 -0
- data/lib/sinatra/accept_media_types.rb +128 -0
- data/lib/sinatra/lazy_auth.rb +56 -0
- data/lib/sinatra/rabbit.rb +273 -0
- data/lib/sinatra/respond_to.rb +272 -0
- data/lib/sinatra/static_assets.rb +83 -0
- data/lib/sinatra/url_for.rb +53 -0
- data/public/favicon.ico +0 -0
- data/public/images/grid.png +0 -0
- data/public/images/logo-wide.png +0 -0
- data/public/images/rails.png +0 -0
- data/public/images/topbar-bg.png +0 -0
- data/public/javascripts/application.js +32 -0
- data/public/javascripts/jquery-1.4.2.min.js +154 -0
- data/public/stylesheets/compiled/application.css +613 -0
- data/public/stylesheets/compiled/ie.css +31 -0
- data/public/stylesheets/compiled/print.css +27 -0
- data/public/stylesheets/compiled/screen.css +456 -0
- data/server.rb +354 -0
- data/support/fedora/deltacloudd +68 -0
- data/support/fedora/rubygem-deltacloud-core.spec +91 -0
- data/tests/api_test.rb +37 -0
- data/tests/hardware_profiles_test.rb +120 -0
- data/tests/images_test.rb +111 -0
- data/tests/instance_states_test.rb +52 -0
- data/tests/instances_test.rb +219 -0
- data/tests/realms_test.rb +78 -0
- data/tests/url_for_test.rb +50 -0
- data/views/accounts/index.html.haml +11 -0
- data/views/accounts/show.html.haml +30 -0
- data/views/api/show.html.haml +15 -0
- data/views/api/show.xml.haml +5 -0
- data/views/docs/collection.html.haml +37 -0
- data/views/docs/collection.xml.haml +14 -0
- data/views/docs/index.html.haml +15 -0
- data/views/docs/index.xml.haml +5 -0
- data/views/docs/operation.html.haml +31 -0
- data/views/docs/operation.xml.haml +10 -0
- data/views/errors/auth_exception.html.haml +8 -0
- data/views/errors/auth_exception.xml.haml +2 -0
- data/views/errors/backend_error.html.haml +19 -0
- data/views/errors/backend_error.xml.haml +8 -0
- data/views/errors/not_found.html.haml +6 -0
- data/views/errors/not_found.xml.haml +2 -0
- data/views/errors/validation_failure.html.haml +11 -0
- data/views/errors/validation_failure.xml.haml +7 -0
- data/views/hardware_profiles/index.html.haml +25 -0
- data/views/hardware_profiles/index.xml.haml +4 -0
- data/views/hardware_profiles/show.html.haml +19 -0
- data/views/hardware_profiles/show.xml.haml +18 -0
- data/views/images/index.html.haml +30 -0
- data/views/images/index.xml.haml +8 -0
- data/views/images/show.html.haml +21 -0
- data/views/images/show.xml.haml +5 -0
- data/views/instance_states/show.gv.erb +45 -0
- data/views/instance_states/show.html.haml +31 -0
- data/views/instance_states/show.xml.haml +8 -0
- data/views/instances/index.html.haml +30 -0
- data/views/instances/index.xml.haml +21 -0
- data/views/instances/new.html.haml +55 -0
- data/views/instances/show.html.haml +43 -0
- data/views/instances/show.xml.haml +49 -0
- data/views/keys/index.html.haml +26 -0
- data/views/keys/index.xml.haml +4 -0
- data/views/keys/new.html.haml +8 -0
- data/views/keys/show.html.haml +22 -0
- data/views/keys/show.xml.haml +20 -0
- data/views/layout.html.haml +26 -0
- data/views/realms/index.html.haml +29 -0
- data/views/realms/index.xml.haml +10 -0
- data/views/realms/show.html.haml +15 -0
- data/views/realms/show.xml.haml +9 -0
- data/views/root/index.html.haml +4 -0
- data/views/storage_snapshots/index.html.haml +20 -0
- data/views/storage_snapshots/index.xml.haml +9 -0
- data/views/storage_snapshots/show.html.haml +14 -0
- data/views/storage_snapshots/show.xml.haml +7 -0
- data/views/storage_volumes/index.html.haml +21 -0
- data/views/storage_volumes/index.xml.haml +13 -0
- data/views/storage_volumes/show.html.haml +20 -0
- data/views/storage_volumes/show.xml.haml +11 -0
- metadata +334 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
require 'sinatra/base'
|
|
2
|
+
require 'sinatra/accept_media_types'
|
|
3
|
+
|
|
4
|
+
# Accept header parsing was looked at but deemed
|
|
5
|
+
# too much of an irregularity to deal with. Problems with the header
|
|
6
|
+
# differences from IE, Firefox, Safari, and every other UA causes
|
|
7
|
+
# problems with the expected output. The general expected behavior
|
|
8
|
+
# would be serve html when no extension provided, but most UAs say
|
|
9
|
+
# they will accept application/xml with out a quality indicator, meaning
|
|
10
|
+
# you'd get the xml block served insead. Just plain retarded, use the
|
|
11
|
+
# extension and you'll never be suprised.
|
|
12
|
+
|
|
13
|
+
module Sinatra
|
|
14
|
+
module RespondTo
|
|
15
|
+
class UnhandledFormat < Sinatra::NotFound; end
|
|
16
|
+
class MissingTemplate < Sinatra::NotFound
|
|
17
|
+
def code; 500 end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
TEXT_MIME_TYPES = [:txt, :html, :js, :json, :xml, :rss, :atom, :css, :asm, :c, :cc, :conf,
|
|
21
|
+
:csv, :cxx, :diff, :dtd, :f, :f77, :f90, :for, :gemspec, :h, :hh, :htm,
|
|
22
|
+
:log, :mathml, :mml, :p, :pas, :pl, :pm, :py, :rake, :rb, :rdf, :rtf, :ru,
|
|
23
|
+
:s, :sgm, :sgml, :sh, :svg, :svgz, :text, :wsdl, :xhtml, :xsl, :xslt, :yaml,
|
|
24
|
+
:yml, :ics, :png]
|
|
25
|
+
|
|
26
|
+
def self.registered(app)
|
|
27
|
+
app.helpers RespondTo::Helpers
|
|
28
|
+
|
|
29
|
+
app.set :default_charset, 'utf-8'
|
|
30
|
+
app.set :default_content, :html
|
|
31
|
+
app.set :assume_xhr_is_js, true
|
|
32
|
+
|
|
33
|
+
# We remove the trailing extension so routes
|
|
34
|
+
# don't have to be of the style
|
|
35
|
+
#
|
|
36
|
+
# get '/resouce.:format'
|
|
37
|
+
#
|
|
38
|
+
# They can instead be of the style
|
|
39
|
+
#
|
|
40
|
+
# get '/resource'
|
|
41
|
+
#
|
|
42
|
+
# and the format will automatically be available in <tt>format</tt>
|
|
43
|
+
app.before do
|
|
44
|
+
# Let through sinatra image urls in development
|
|
45
|
+
next if self.class.development? && request.path_info =~ %r{/__sinatra__/.*?.png}
|
|
46
|
+
|
|
47
|
+
unless options.static? && options.public? && (request.get? || request.head?) && static_file?(request.path_info)
|
|
48
|
+
rpi = request.path_info.sub(%r{\.([^\./]+)$}, '')
|
|
49
|
+
|
|
50
|
+
if (not $1) or ($1 and TEXT_MIME_TYPES.include?($1.to_sym))
|
|
51
|
+
request.path_info, ext = rpi, nil
|
|
52
|
+
if ! $1.nil?
|
|
53
|
+
ext = $1
|
|
54
|
+
elsif env['HTTP_ACCEPT'].nil? || env['HTTP_ACCEPT'].empty?
|
|
55
|
+
ext = options.default_content
|
|
56
|
+
end
|
|
57
|
+
if ext
|
|
58
|
+
@mime_types = [ Helpers::mime_type(ext) ]
|
|
59
|
+
format ext
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
app.configure :development do |dev|
|
|
66
|
+
dev.error UnhandledFormat do
|
|
67
|
+
content_type :html, :charset => 'utf-8'
|
|
68
|
+
|
|
69
|
+
(<<-HTML).gsub(/^ {10}/, '')
|
|
70
|
+
<!DOCTYPE html>
|
|
71
|
+
<html>
|
|
72
|
+
<head>
|
|
73
|
+
<style type="text/css">
|
|
74
|
+
body { text-align:center;font-family:helvetica,arial;font-size:22px;
|
|
75
|
+
color:#888;margin:20px}
|
|
76
|
+
#c {margin:0 auto;width:500px;text-align:left}
|
|
77
|
+
</style>
|
|
78
|
+
</head>
|
|
79
|
+
<body>
|
|
80
|
+
<h2>Sinatra doesn't know this ditty.</h2>
|
|
81
|
+
<img src='/__sinatra__/404.png'>
|
|
82
|
+
<div id="c">
|
|
83
|
+
Try this:
|
|
84
|
+
<pre>#{request.request_method.downcase} '#{request.path_info}' do\n respond_to do |wants|\n wants.#{format} { "Hello World" }\n end\nend</pre>
|
|
85
|
+
</div>
|
|
86
|
+
</body>
|
|
87
|
+
</html>
|
|
88
|
+
HTML
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
dev.error MissingTemplate do
|
|
92
|
+
content_type :html, :charset => 'utf-8'
|
|
93
|
+
response.status = request.env['sinatra.error'].code
|
|
94
|
+
|
|
95
|
+
engine = request.env['sinatra.error'].message.split('.').last
|
|
96
|
+
engine = 'haml' unless ['haml', 'builder', 'erb'].include? engine
|
|
97
|
+
|
|
98
|
+
path = File.basename(request.path_info)
|
|
99
|
+
path = "root" if path.nil? || path.empty?
|
|
100
|
+
|
|
101
|
+
format = engine == 'builder' ? 'xml' : 'html'
|
|
102
|
+
|
|
103
|
+
layout = case engine
|
|
104
|
+
when 'haml' then "!!!\n%html\n %body= yield"
|
|
105
|
+
when 'erb' then "<html>\n <body>\n <%= yield %>\n </body>\n</html>"
|
|
106
|
+
when 'builder' then ::Sinatra::VERSION =~ /^1.0/ ? "xml << yield" : "builder do |xml|\n xml << yield\nend"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
layout = "<small>app.#{format}.#{engine}</small>\n<pre>#{escape_html(layout)}</pre>"
|
|
110
|
+
|
|
111
|
+
(<<-HTML).gsub(/^ {10}/, '')
|
|
112
|
+
<!DOCTYPE html>
|
|
113
|
+
<html>
|
|
114
|
+
<head>
|
|
115
|
+
<style type="text/css">
|
|
116
|
+
body { text-align:center;font-family:helvetica,arial;font-size:22px;
|
|
117
|
+
color:#888;margin:20px}
|
|
118
|
+
#c {margin:0 auto;width:500px;text-align:left;}
|
|
119
|
+
small {float:right;clear:both;}
|
|
120
|
+
pre {clear:both;}
|
|
121
|
+
</style>
|
|
122
|
+
</head>
|
|
123
|
+
<body>
|
|
124
|
+
<h2>Sinatra can't find #{request.env['sinatra.error'].message}</h2>
|
|
125
|
+
<img src='/__sinatra__/500.png'>
|
|
126
|
+
<div id="c">
|
|
127
|
+
Try this:<br />
|
|
128
|
+
#{layout}
|
|
129
|
+
<small>#{path}.#{format}.#{engine}</small>
|
|
130
|
+
<pre>Hello World!</pre>
|
|
131
|
+
<small>application.rb</small>
|
|
132
|
+
<pre>#{request.request_method.downcase} '#{request.path_info}' do\n respond_to do |wants|\n wants.#{engine == 'builder' ? 'xml' : 'html'} { #{engine} :#{path}#{",\n#{' '*32}layout => :app" if layout} }\n end\nend</pre>
|
|
133
|
+
</div>
|
|
134
|
+
</body>
|
|
135
|
+
</html>
|
|
136
|
+
HTML
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
app.class_eval do
|
|
142
|
+
private
|
|
143
|
+
def accept_list
|
|
144
|
+
@mime_types || Rack::AcceptMediaTypes.new(env['HTTP_ACCEPT'] || '')
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Changes in 1.0 Sinatra reuse render for layout so we store
|
|
148
|
+
# the original value to tell us if this is an automatic attempt
|
|
149
|
+
# to do a layout call. If it is, it might fail with Errno::ENOENT
|
|
150
|
+
# and we want to pass that back to sinatra since it isn't a MissingTemplate
|
|
151
|
+
# error
|
|
152
|
+
def render_with_format(*args, &block)
|
|
153
|
+
assumed_layout = args[1] == :layout
|
|
154
|
+
args[1] = "#{args[1]}.#{format}".to_sym if args[1].is_a?(::Symbol)
|
|
155
|
+
render_without_format *args, &block
|
|
156
|
+
rescue Errno::ENOENT => e
|
|
157
|
+
raise MissingTemplate, "#{args[1]}.#{args[0]}" unless assumed_layout
|
|
158
|
+
raise e
|
|
159
|
+
end
|
|
160
|
+
alias_method :render_without_format, :render
|
|
161
|
+
alias_method :render, :render_with_format
|
|
162
|
+
|
|
163
|
+
if ::Sinatra::VERSION =~ /^0\.9/
|
|
164
|
+
def lookup_layout_with_format(*args)
|
|
165
|
+
args[1] = "#{args[1]}.#{format}".to_sym if args[1].is_a?(::Symbol)
|
|
166
|
+
lookup_layout_without_format *args
|
|
167
|
+
end
|
|
168
|
+
alias_method :lookup_layout_without_format, :lookup_layout
|
|
169
|
+
alias_method :lookup_layout, :lookup_layout_with_format
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
module Helpers
|
|
175
|
+
# Patch the content_type function to remember the set type
|
|
176
|
+
# This helps cut down on time in the format helper so it
|
|
177
|
+
# doesn't have to do a reverse lookup on the header
|
|
178
|
+
def self.included(klass)
|
|
179
|
+
klass.class_eval do
|
|
180
|
+
def content_type_with_save(*args)
|
|
181
|
+
content_type_without_save *args
|
|
182
|
+
@_format = args.first.to_sym
|
|
183
|
+
response['Content-Type']
|
|
184
|
+
end
|
|
185
|
+
alias_method :content_type_without_save, :content_type
|
|
186
|
+
alias_method :content_type, :content_type_with_save
|
|
187
|
+
end if ::Sinatra::VERSION =~ /^1.0/
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def self.mime_type(sym)
|
|
191
|
+
::Sinatra::Base.respond_to?(:mime_type) && ::Sinatra::Base.mime_type(sym) || ::Sinatra::Base.media_type(sym)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def format(val=nil)
|
|
195
|
+
unless val.nil?
|
|
196
|
+
mime_type = ::Sinatra::RespondTo::Helpers.mime_type(val)
|
|
197
|
+
fail "Unknown media type #{val}\nTry registering the extension with a mime type" if mime_type.nil?
|
|
198
|
+
|
|
199
|
+
@_format = val.to_sym
|
|
200
|
+
response['Content-Type'].sub!(/^[^;]+/, mime_type)
|
|
201
|
+
charset options.default_charset if Sinatra::RespondTo::TEXT_MIME_TYPES.include?(format) and format!=:png
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
@_format
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# This is mostly just a helper so request.path_info isn't changed when
|
|
208
|
+
# serving files from the public directory
|
|
209
|
+
def static_file?(path)
|
|
210
|
+
public_dir = File.expand_path(options.public)
|
|
211
|
+
path = File.expand_path(File.join(public_dir, unescape(path)))
|
|
212
|
+
|
|
213
|
+
path[0, public_dir.length] == public_dir && File.file?(path)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def charset(val=nil)
|
|
217
|
+
fail "Content-Type must be set in order to specify a charset" if response['Content-Type'].nil?
|
|
218
|
+
|
|
219
|
+
if response['Content-Type'] =~ /charset=[^;]+/
|
|
220
|
+
response['Content-Type'].sub!(/charset=[^;]+/, (val == '' && '') || "charset=#{val}")
|
|
221
|
+
else
|
|
222
|
+
response['Content-Type'] += ";charset=#{val}"
|
|
223
|
+
end unless val.nil?
|
|
224
|
+
|
|
225
|
+
response['Content-Type'][/charset=([^;]+)/, 1]
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def respond_to(&block)
|
|
229
|
+
wants = Format.new
|
|
230
|
+
yield wants
|
|
231
|
+
fmt, type, handler = match_accept_type(accept_list, wants)
|
|
232
|
+
raise UnhandledFormat if fmt.nil?
|
|
233
|
+
format fmt
|
|
234
|
+
handler.nil? ? nil : handler.call
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def match_accept_type(mime_types, format)
|
|
238
|
+
selected = []
|
|
239
|
+
accepted_types = mime_types.map {|type| Regexp.escape(type).gsub(/\\\*/,'.*') }
|
|
240
|
+
# Fix for Chrome based browsers which returns XML when 'xhtml' is requested.
|
|
241
|
+
if env['HTTP_USER_AGENT'] =~ /Chrome/ and accepted_types.size>1
|
|
242
|
+
accepted_types[0], accepted_types[1] = accepted_types[1], accepted_types[0]
|
|
243
|
+
if accepted_types[0].eql?('application/xhtml\\+xml')
|
|
244
|
+
accepted_types[0] = 'text/html'
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
accepted_types.each do |at|
|
|
248
|
+
format.each do |fmt, ht, handler|
|
|
249
|
+
(selected = [fmt, ht, handler]) and break if ht.match(at)
|
|
250
|
+
end
|
|
251
|
+
break unless selected.empty?
|
|
252
|
+
end
|
|
253
|
+
selected
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# NOTE Array instead of hash because order matters (wildcard type
|
|
257
|
+
# matches first handler)
|
|
258
|
+
class Format < Array #:nodoc:
|
|
259
|
+
def method_missing(format, *args, &handler)
|
|
260
|
+
mt = Sinatra::RespondTo::Helpers.mime_type(format)
|
|
261
|
+
if mt.nil?
|
|
262
|
+
Sinatra::Base.send(:fail, "Unknown media type for respond_to: #{format}\nTry registering the extension with a mime type")
|
|
263
|
+
end
|
|
264
|
+
self << [format.to_s, mt, handler]
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
Rack::Mime::MIME_TYPES.merge!({ ".gv" => "text/plain" })
|
|
272
|
+
Sinatra::Application.register Sinatra::RespondTo
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'sinatra/base'
|
|
2
|
+
require 'sinatra/url_for'
|
|
3
|
+
|
|
4
|
+
module Sinatra
|
|
5
|
+
module StaticAssets
|
|
6
|
+
module Helpers
|
|
7
|
+
# In HTML <link> and <img> tags have no end tag.
|
|
8
|
+
# In XHTML, on the contrary, these tags must be properly closed.
|
|
9
|
+
#
|
|
10
|
+
# We can choose the appropriate behaviour with +closed+ option:
|
|
11
|
+
#
|
|
12
|
+
# image_tag "/images/foo.png", :alt => "Foo itself", :closed => true
|
|
13
|
+
#
|
|
14
|
+
# The default value of +closed+ option is +false+.
|
|
15
|
+
#
|
|
16
|
+
def image_tag(source, options = {})
|
|
17
|
+
options[:src] = url_for(source)
|
|
18
|
+
tag("img", options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def stylesheet_link_tag(*sources)
|
|
22
|
+
list, options = extract_options(sources)
|
|
23
|
+
list.collect { |source| stylesheet_tag(source, options) }.join("\n")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def javascript_script_tag(*sources)
|
|
27
|
+
list, options = extract_options(sources)
|
|
28
|
+
list.collect { |source| javascript_tag(source, options) }.join("\n")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def link_to(desc, url, options = {})
|
|
32
|
+
tag("a", options.merge(:href => url_for(url))) do
|
|
33
|
+
desc
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def tag(name, local_options = {})
|
|
40
|
+
start_tag = "<#{name}#{tag_options(local_options) if local_options}"
|
|
41
|
+
if block_given?
|
|
42
|
+
content = yield
|
|
43
|
+
"#{start_tag}>#{content}</#{name}>"
|
|
44
|
+
else
|
|
45
|
+
"#{start_tag}#{"/" if options.xhtml}>"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def tag_options(options)
|
|
50
|
+
unless options.empty?
|
|
51
|
+
attrs = []
|
|
52
|
+
attrs = options.map { |key, value| %(#{key}="#{Rack::Utils.escape_html(value)}") }
|
|
53
|
+
" #{attrs.sort * ' '}" unless attrs.empty?
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def stylesheet_tag(source, options = {})
|
|
58
|
+
tag("link", { :type => "text/css",
|
|
59
|
+
:charset => "utf-8", :media => "screen", :rel => "stylesheet",
|
|
60
|
+
:href => url_for(source) }.merge(options))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def javascript_tag(source, options = {})
|
|
64
|
+
tag("script", { :type => "text/javascript", :charset => "utf-8",
|
|
65
|
+
:src => url_for(source) }.merge(options)) do
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def extract_options(a)
|
|
70
|
+
opts = a.last.is_a?(::Hash) ? a.pop : {}
|
|
71
|
+
[a, opts]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.registered(app)
|
|
77
|
+
app.helpers StaticAssets::Helpers
|
|
78
|
+
app.disable :xhtml
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
register StaticAssets
|
|
83
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
module Sinatra
|
|
4
|
+
module UrlForHelper
|
|
5
|
+
# Construct a link to +url_fragment+, which should be given relative to
|
|
6
|
+
# the base of this Sinatra app. The mode should be either
|
|
7
|
+
# <code>:path_only</code>, which will generate an absolute path within
|
|
8
|
+
# the current domain (the default), or <code>:full</code>, which will
|
|
9
|
+
# include the site name and port number. (The latter is typically
|
|
10
|
+
# necessary for links in RSS feeds.) Example usage:
|
|
11
|
+
#
|
|
12
|
+
# url_for "/" # Returns "/myapp/"
|
|
13
|
+
# url_for "/foo" # Returns "/myapp/foo"
|
|
14
|
+
# url_for "/foo", :full # Returns "http://example.com/myapp/foo"
|
|
15
|
+
#--
|
|
16
|
+
# See README.rdoc for a list of some of the people who helped me clean
|
|
17
|
+
# up earlier versions of this code.
|
|
18
|
+
def url_for url_fragment, mode=:path_only
|
|
19
|
+
case mode
|
|
20
|
+
when :path_only
|
|
21
|
+
base = request.script_name
|
|
22
|
+
when :full
|
|
23
|
+
scheme = request.scheme
|
|
24
|
+
if (scheme == 'http' && request.port == 80 ||
|
|
25
|
+
scheme == 'https' && request.port == 443)
|
|
26
|
+
port = ""
|
|
27
|
+
else
|
|
28
|
+
port = ":#{request.port}"
|
|
29
|
+
end
|
|
30
|
+
request_host = HOSTNAME ? HOSTNAME : request.host
|
|
31
|
+
base = "#{scheme}://#{request_host}#{port}#{request.script_name}"
|
|
32
|
+
else
|
|
33
|
+
raise TypeError, "Unknown url_for mode #{mode}"
|
|
34
|
+
end
|
|
35
|
+
url_escape = URI.escape(url_fragment)
|
|
36
|
+
# Don't add the base fragment if url_for gets called more than once
|
|
37
|
+
# per url or the url_fragment passed in is an absolute url
|
|
38
|
+
if url_escape.match(/^#{base}/) or url_escape.match(/^http/)
|
|
39
|
+
url_escape
|
|
40
|
+
else
|
|
41
|
+
"#{base}#{url_escape}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def root_url
|
|
46
|
+
url_for '/'
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
helpers UrlForHelper
|
|
53
|
+
end
|
data/public/favicon.ico
ADDED
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Place your application-specific JavaScript functions and classes here
|
|
2
|
+
// This file is automatically included by javascript_include_tag :defaults
|
|
3
|
+
|
|
4
|
+
$(document).ready(function() {
|
|
5
|
+
|
|
6
|
+
$("a.delete").click(function(e) {
|
|
7
|
+
var original_url = $(this).attr('href')
|
|
8
|
+
$.ajax({
|
|
9
|
+
url : original_url,
|
|
10
|
+
type : 'DELETE',
|
|
11
|
+
cache : false,
|
|
12
|
+
success: function(data) {
|
|
13
|
+
window.location = original_url.replace(/\/([\w_-]+)$/i, '')
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
return false;
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
$("a.post").click(function(e) {
|
|
20
|
+
var original_url = $(this).attr('href')
|
|
21
|
+
$.ajax({
|
|
22
|
+
url : original_url,
|
|
23
|
+
type : 'POST',
|
|
24
|
+
dataType : 'xml',
|
|
25
|
+
success: function(data) {
|
|
26
|
+
window.location = original_url.replace(/\/([\w_-]+)$/i, '')
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
return false;
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
})
|