crystal 0.0.1 → 0.0.2

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/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *~
2
+ .DS_Store
3
+ Thumbs.db
@@ -0,0 +1,25 @@
1
+ require 'crystal/support/active_support'
2
+
3
+ require 'ruby_ext'
4
+
5
+ require 'crystal/rack/adapter'
6
+ require 'crystal/remote'
7
+ require 'crystal/setting'
8
+
9
+ module Crystal
10
+ VERSION = '0.0.1'
11
+
12
+ class << self
13
+ def setting
14
+ @setting ||= Setting.new
15
+ end
16
+
17
+ def load_environment
18
+ end
19
+
20
+ def run
21
+ load_environment
22
+ Crystal::Adapter.run
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,109 @@
1
+ # Use the specified Rack middleware
2
+ def use(middleware, *args, &block)
3
+ @prototype = nil
4
+ @middleware << [middleware, args, block]
5
+ end
6
+
7
+
8
+ def compile(path)
9
+ keys = []
10
+ if path.respond_to? :to_str
11
+ special_chars = %w{. + ( )}
12
+ pattern =
13
+ path.to_str.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
14
+ case match
15
+ when "*"
16
+ keys << 'splat'
17
+ "(.*?)"
18
+ when *special_chars
19
+ Regexp.escape(match)
20
+ else
21
+ keys << $2[1..-1]
22
+ "([^/?&#]+)"
23
+ end
24
+ end
25
+ [/^#{pattern}$/, keys]
26
+ elsif path.respond_to?(:keys) && path.respond_to?(:match)
27
+ [path, path.keys]
28
+ elsif path.respond_to? :match
29
+ [path, keys]
30
+ else
31
+ raise TypeError, path
32
+ end
33
+ end
34
+
35
+ def compile!(verb, path, block)
36
+ method_name = "#{verb} #{path}"
37
+ define_method(method_name, &block)
38
+ unbound_method = instance_method method_name
39
+ remove_method method_name
40
+ [block.arity != 0 ?
41
+ proc { unbound_method.bind(self).call(*@block_params) } :
42
+ proc { unbound_method.bind(self).call }, *compile(path)]
43
+ end
44
+
45
+ # Define a named template. The block must return the template source.
46
+ def template(name, &block)
47
+ filename, line = caller_locations.first
48
+ templates[name] = [block, filename, line.to_i]
49
+ end
50
+
51
+
52
+ # Define a custom error handler. Optionally takes either an Exception
53
+ # class, or an HTTP status code to specify which errors should be
54
+ # handled.
55
+ def error(codes=Exception, &block)
56
+ Array(codes).each { |code| @errors[code] = block }
57
+ end
58
+
59
+ # Sugar for `error(404) { ... }`
60
+ def not_found(&block)
61
+ error 404, &block
62
+ end
63
+
64
+
65
+ # Find an custom error block for the key(s) specified.
66
+ def error_block!(*keys)
67
+ keys.each do |key|
68
+ base = self.class
69
+ while base.respond_to?(:errors)
70
+ if block = base.errors[key]
71
+ # found a handler, eval and return result
72
+ return instance_eval(&block)
73
+ else
74
+ base = base.superclass
75
+ end
76
+ end
77
+ end
78
+ nil
79
+ end
80
+
81
+ def dump_errors!(boom)
82
+ msg = ["#{boom.class} - #{boom.message}:",
83
+ *boom.backtrace].join("\n ")
84
+ @env['rack.errors'].puts(msg)
85
+ end
86
+
87
+ # Exit the current block, halts any further processing
88
+ # of the request, and returns the specified response.
89
+ def halt(*response)
90
+ response = response.first if response.length == 1
91
+ throw :halt, response
92
+ end
93
+
94
+ # Pass control to the next matching route.
95
+ # If there are no more matching routes, Sinatra will
96
+ # return a 404 response.
97
+ def pass(&block)
98
+ throw :pass, block
99
+ end
100
+
101
+ # Forward the request to the downstream app -- middleware only.
102
+ def forward
103
+ fail "downstream app not set" unless @app.respond_to? :call
104
+ status, headers, body = @app.call(@request.env)
105
+ @response.status = status
106
+ @response.body = body
107
+ @response.headers.merge! headers
108
+ nil
109
+ end
@@ -0,0 +1,213 @@
1
+ # Methods available to routes, before/after filters, and views.
2
+ module Helpers
3
+ # Lookup or register a mime type in Rack's mime registry.
4
+ def mime_type(type, value=nil)
5
+ return type if type.nil? || type.to_s.include?('/')
6
+ type = ".#{type}" unless type.to_s[0] == ?.
7
+ return Rack::Mime.mime_type(type, nil) unless value
8
+ Rack::Mime::MIME_TYPES[type] = value
9
+ end
10
+
11
+ # Set or retrieve the response status code.
12
+ def status(value=nil)
13
+ response.status = value if value
14
+ response.status
15
+ end
16
+
17
+ # Set or retrieve the response body. When a block is given,
18
+ # evaluation is deferred until the body is read with #each.
19
+ def body(value=nil, &block)
20
+ if block_given?
21
+ def block.each ; yield call ; end
22
+ response.body = block
23
+ else
24
+ response.body = value
25
+ end
26
+ end
27
+
28
+ # Halt processing and redirect to the URI provided.
29
+ def redirect(uri, *args)
30
+ status 302
31
+ response['Location'] = uri
32
+ halt(*args)
33
+ end
34
+
35
+ # Halt processing and return the error status provided.
36
+ def error(code, body=nil)
37
+ code, body = 500, code.to_str if code.respond_to? :to_str
38
+ response.body = body unless body.nil?
39
+ halt code
40
+ end
41
+
42
+ # Halt processing and return a 404 Not Found.
43
+ def not_found(body=nil)
44
+ error 404, body
45
+ end
46
+
47
+ # Set multiple response headers with Hash.
48
+ def headers(hash=nil)
49
+ response.headers.merge! hash if hash
50
+ response.headers
51
+ end
52
+
53
+ # Access the underlying Rack session.
54
+ def session
55
+ env['rack.session'] ||= {}
56
+ end
57
+
58
+ # Look up a media type by file extension in Rack's mime registry.
59
+ def mime_type(type)
60
+ Base.mime_type(type)
61
+ end
62
+
63
+ # Set the Content-Type of the response body given a media type or file
64
+ # extension.
65
+ def content_type(type, params={})
66
+ mime_type = mime_type(type)
67
+ fail "Unknown media type: %p" % type if mime_type.nil?
68
+ if params.any?
69
+ params = params.collect { |kv| "%s=%s" % kv }.join(', ')
70
+ response['Content-Type'] = [mime_type, params].join(";")
71
+ else
72
+ response['Content-Type'] = mime_type
73
+ end
74
+ end
75
+
76
+ # Set the Content-Disposition to "attachment" with the specified filename,
77
+ # instructing the user agents to prompt to save.
78
+ def attachment(filename=nil)
79
+ response['Content-Disposition'] = 'attachment'
80
+ if filename
81
+ params = '; filename="%s"' % File.basename(filename)
82
+ response['Content-Disposition'] << params
83
+ end
84
+ end
85
+
86
+ # Use the contents of the file at +path+ as the response body.
87
+ def send_file(path, opts={})
88
+ stat = File.stat(path)
89
+ last_modified stat.mtime
90
+
91
+ content_type mime_type(opts[:type]) ||
92
+ mime_type(File.extname(path)) ||
93
+ response['Content-Type'] ||
94
+ 'application/octet-stream'
95
+
96
+ response['Content-Length'] ||= (opts[:length] || stat.size).to_s
97
+
98
+ if opts[:disposition] == 'attachment' || opts[:filename]
99
+ attachment opts[:filename] || path
100
+ elsif opts[:disposition] == 'inline'
101
+ response['Content-Disposition'] = 'inline'
102
+ end
103
+
104
+ halt StaticFile.open(path, 'rb')
105
+ rescue Errno::ENOENT
106
+ not_found
107
+ end
108
+
109
+ # Rack response body used to deliver static files. The file contents are
110
+ # generated iteratively in 8K chunks.
111
+ class StaticFile < ::File #:nodoc:
112
+ alias_method :to_path, :path
113
+ def each
114
+ rewind
115
+ while buf = read(8192)
116
+ yield buf
117
+ end
118
+ end
119
+ end
120
+
121
+ # Specify response freshness policy for HTTP caches (Cache-Control header).
122
+ # Any number of non-value directives (:public, :private, :no_cache,
123
+ # :no_store, :must_revalidate, :proxy_revalidate) may be passed along with
124
+ # a Hash of value directives (:max_age, :min_stale, :s_max_age).
125
+ #
126
+ # cache_control :public, :must_revalidate, :max_age => 60
127
+ # => Cache-Control: public, must-revalidate, max-age=60
128
+ #
129
+ # See RFC 2616 / 14.9 for more on standard cache control directives:
130
+ # http://tools.ietf.org/html/rfc2616#section-14.9.1
131
+ def cache_control(*values)
132
+ if values.last.kind_of?(Hash)
133
+ hash = values.pop
134
+ hash.reject! { |k,v| v == false }
135
+ hash.reject! { |k,v| values << k if v == true }
136
+ else
137
+ hash = {}
138
+ end
139
+
140
+ values = values.map { |value| value.to_s.tr('_','-') }
141
+ hash.each { |k,v| values << [k.to_s.tr('_', '-'), v].join('=') }
142
+
143
+ response['Cache-Control'] = values.join(', ') if values.any?
144
+ end
145
+
146
+ # Set the Expires header and Cache-Control/max-age directive. Amount
147
+ # can be an integer number of seconds in the future or a Time object
148
+ # indicating when the response should be considered "stale". The remaining
149
+ # "values" arguments are passed to the #cache_control helper:
150
+ #
151
+ # expires 500, :public, :must_revalidate
152
+ # => Cache-Control: public, must-revalidate, max-age=60
153
+ # => Expires: Mon, 08 Jun 2009 08:50:17 GMT
154
+ #
155
+ def expires(amount, *values)
156
+ values << {} unless values.last.kind_of?(Hash)
157
+
158
+ if amount.respond_to?(:to_time)
159
+ max_age = amount.to_time - Time.now
160
+ time = amount.to_time
161
+ else
162
+ max_age = amount
163
+ time = Time.now + amount
164
+ end
165
+
166
+ values.last.merge!(:max_age => max_age)
167
+ cache_control(*values)
168
+
169
+ response['Expires'] = time.httpdate
170
+ end
171
+
172
+ # Set the last modified time of the resource (HTTP 'Last-Modified' header)
173
+ # and halt if conditional GET matches. The +time+ argument is a Time,
174
+ # DateTime, or other object that responds to +to_time+.
175
+ #
176
+ # When the current request includes an 'If-Modified-Since' header that
177
+ # matches the time specified, execution is immediately halted with a
178
+ # '304 Not Modified' response.
179
+ def last_modified(time)
180
+ return unless time
181
+ time = time.to_time if time.respond_to?(:to_time)
182
+ time = time.httpdate if time.respond_to?(:httpdate)
183
+ response['Last-Modified'] = time
184
+ halt 304 if time == request.env['HTTP_IF_MODIFIED_SINCE']
185
+ time
186
+ end
187
+
188
+ # Set the response entity tag (HTTP 'ETag' header) and halt if conditional
189
+ # GET matches. The +value+ argument is an identifier that uniquely
190
+ # identifies the current version of the resource. The +kind+ argument
191
+ # indicates whether the etag should be used as a :strong (default) or :weak
192
+ # cache validator.
193
+ #
194
+ # When the current request includes an 'If-None-Match' header with a
195
+ # matching etag, execution is immediately halted. If the request method is
196
+ # GET or HEAD, a '304 Not Modified' response is sent.
197
+ def etag(value, kind=:strong)
198
+ raise TypeError, ":strong or :weak expected" if ![:strong,:weak].include?(kind)
199
+ value = '"%s"' % value
200
+ value = 'W/' + value if kind == :weak
201
+ response['ETag'] = value
202
+
203
+ # Conditional GET check
204
+ if etags = env['HTTP_IF_NONE_MATCH']
205
+ etags = etags.split(/\s*,\s*/)
206
+ halt 304 if etags.include?(value) || etags.include?('*')
207
+ end
208
+ end
209
+
210
+ ## Sugar for redirect (example: redirect back)
211
+ def back ; request.referer ; end
212
+
213
+ end
@@ -0,0 +1,60 @@
1
+ require 'crystal/rack/support'
2
+ require 'crystal/rack/rack_app'
3
+
4
+ module Crystal
5
+ class Adapter
6
+ SERVERS = %w{mongrel thin webrick}
7
+
8
+ class Callback
9
+ def initialize app; end
10
+ def self.call env; Crystal::Adapter.call env end
11
+ end
12
+
13
+ class << self
14
+
15
+ def run
16
+ app = build_app
17
+ handler = detect_rack_handler
18
+ handler_name = handler.name.gsub(/.*::/, '')
19
+ puts " Crystal #{Crystal::VERSION} started on #{Crystal.setting.port} in #{Crystal.setting.environment} mode" unless handler_name =~/cgi/i
20
+ handler.run app, :Host => Crystal.setting.host, :Port => Crystal.setting.port do |server|
21
+ [:INT, :TERM].each {|sig| trap(sig){quit!(server, handler_name)}}
22
+ end
23
+ rescue Errno::EADDRINUSE => e
24
+ puts " #{port} is taken!"
25
+ end
26
+
27
+ def quit!(server, handler_name)
28
+ ## Use thins' hard #stop! if available, otherwise just #stop
29
+ server.respond_to?(:stop!) ? server.stop! : server.stop
30
+ puts "\n Crystal stopped" unless handler_name =~/cgi/i
31
+ end
32
+
33
+ protected
34
+ def build_app
35
+ builder = Rack::Builder.new
36
+ builder.use Rack::Session::Cookie if Crystal.setting.session?
37
+ # builder.use Rack::CommonLogger
38
+ builder.use Rack::MethodOverride
39
+ # builder.use ShowExceptions if Crystal.setting.show_exceptions?
40
+
41
+ # TODO add middleware here
42
+
43
+ builder.run Crystal::RackApp.new
44
+ builder.to_app
45
+ end
46
+
47
+ def detect_rack_handler
48
+ SERVERS.each do |server_name|
49
+ begin
50
+ return Rack::Handler.get(server_name.downcase)
51
+ rescue LoadError
52
+ rescue NameError
53
+ end
54
+ end
55
+ fail " Server handler (#{servers.join(',')}) not found."
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,27 @@
1
+ # Attempt to serve static files from public directory. Throws :halt when
2
+ # a matching file is found, returns nil otherwise.
3
+ def static!
4
+ return if (public_dir = settings.public).nil?
5
+ public_dir = File.expand_path(public_dir)
6
+
7
+ path = File.expand_path(public_dir + unescape(request.path_info))
8
+ return if path[0, public_dir.length] != public_dir
9
+ return unless File.file?(path)
10
+
11
+ env['sinatra.static_file'] = path
12
+ send_file path, :disposition => nil
13
+ end
14
+
15
+
16
+ # Dispatch a request with error handling.
17
+ def dispatch!
18
+ static! if settings.static? && (request.get? || request.head?)
19
+ filter! :before
20
+ route!
21
+ rescue NotFound => boom
22
+ handle_not_found!(boom)
23
+ rescue ::Exception => boom
24
+ handle_exception!(boom)
25
+ ensure
26
+ filter! :after unless env['sinatra.static_file']
27
+ end
@@ -0,0 +1,94 @@
1
+ module Crystal
2
+ class RackApp
3
+
4
+ def initialize
5
+ @monitor = Monitor.new
6
+ end
7
+
8
+ def call env
9
+ @monitor.synchronize do
10
+ p :here
11
+ [200, {"Content-Type" => "text/plain"}, ["Hello world!"]]
12
+
13
+ # @env = env
14
+ # @request = Request.new(env)
15
+ # @response = Response.new
16
+ # @params = indifferent_params(@request.params)
17
+ # template_cache.clear if settings.reload_templates
18
+ #
19
+ # invoke { dispatch! }
20
+ # invoke { error_block!(response.status) }
21
+ #
22
+ # status, header, body = @response.finish
23
+ #
24
+ # # Never produce a body on HEAD requests. Do retain the Content-Length
25
+ # # unless it's "0", in which case we assume it was calculated erroneously
26
+ # # for a manual HEAD response and remove it entirely.
27
+ # if @env['REQUEST_METHOD'] == 'HEAD'
28
+ # body = []
29
+ # header.delete('Content-Length') if header['Content-Length'] == '0'
30
+ # end
31
+ #
32
+ # [status, header, body]
33
+ end
34
+ end
35
+
36
+ # def handle_not_found!(boom)
37
+ # @env['sinatra.error'] = boom
38
+ # @response.status = 404
39
+ # @response.headers['X-Cascade'] = 'pass'
40
+ # @response.body = ['<h1>Not Found</h1>']
41
+ # error_block! boom.class, NotFound
42
+ # end
43
+ #
44
+ # def handle_exception!(boom)
45
+ # @env['sinatra.error'] = boom
46
+ #
47
+ # dump_errors!(boom) if settings.dump_errors?
48
+ # raise boom if settings.show_exceptions?
49
+ #
50
+ # @response.status = 500
51
+ # if res = error_block!(boom.class)
52
+ # res
53
+ # elsif settings.raise_errors?
54
+ # raise boom
55
+ # else
56
+ # error_block!(Exception)
57
+ # end
58
+ # end
59
+
60
+ # Run the block with 'throw :halt' support and apply result to the response.
61
+ # def invoke(&block)
62
+ # res = catch(:halt) { instance_eval(&block) }
63
+ # return if res.nil?
64
+ #
65
+ # case
66
+ # when res.respond_to?(:to_str)
67
+ # @response.body = [res]
68
+ # when res.respond_to?(:to_ary)
69
+ # res = res.to_ary
70
+ # if Fixnum === res.first
71
+ # if res.length == 3
72
+ # @response.status, headers, body = res
73
+ # @response.body = body if body
74
+ # headers.each { |k, v| @response.headers[k] = v } if headers
75
+ # elsif res.length == 2
76
+ # @response.status = res.first
77
+ # @response.body = res.last
78
+ # else
79
+ # raise TypeError, "#{res.inspect} not supported"
80
+ # end
81
+ # else
82
+ # @response.body = res
83
+ # end
84
+ # when res.respond_to?(:each)
85
+ # @response.body = res
86
+ # when (100...599) === res
87
+ # @response.status = res
88
+ # end
89
+ #
90
+ # res
91
+ # end
92
+
93
+ end
94
+ end
@@ -0,0 +1,307 @@
1
+ require 'rack/showexceptions'
2
+
3
+ module Sinatra
4
+ class ShowExceptions < Rack::ShowExceptions
5
+ def initialize(app)
6
+ @app = app
7
+ @template = ERB.new(TEMPLATE)
8
+ end
9
+
10
+ def frame_class(frame)
11
+ if frame.filename =~ /lib\/sinatra.*\.rb/
12
+ "framework"
13
+ elsif (defined?(Gem) && frame.filename.include?(Gem.dir)) ||
14
+ frame.filename =~ /\/bin\/(\w+)$/
15
+ "system"
16
+ else
17
+ "app"
18
+ end
19
+ end
20
+
21
+ TEMPLATE = <<HTML
22
+ <!DOCTYPE html>
23
+ <html>
24
+ <head>
25
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
26
+ <title><%=h exception.class %> at <%=h path %></title>
27
+
28
+ <script type="text/javascript">
29
+ //<!--
30
+ function toggle(id) {
31
+ var pre = document.getElementById("pre-" + id);
32
+ var post = document.getElementById("post-" + id);
33
+ var context = document.getElementById("context-" + id);
34
+
35
+ if (pre.style.display == 'block') {
36
+ pre.style.display = 'none';
37
+ post.style.display = 'none';
38
+ context.style.background = "none";
39
+ } else {
40
+ pre.style.display = 'block';
41
+ post.style.display = 'block';
42
+ context.style.background = "#fffed9";
43
+ }
44
+ }
45
+
46
+ function toggleBacktrace(){
47
+ var bt = document.getElementById("backtrace");
48
+ var toggler = document.getElementById("expando");
49
+
50
+ if (bt.className == 'condensed') {
51
+ bt.className = 'expanded';
52
+ toggler.innerHTML = "(condense)";
53
+ } else {
54
+ bt.className = 'condensed';
55
+ toggler.innerHTML = "(expand)";
56
+ }
57
+ }
58
+ //-->
59
+ </script>
60
+
61
+ <style type="text/css" media="screen">
62
+ * {margin: 0; padding: 0; border: 0; outline: 0;}
63
+ div.clear {clear: both;}
64
+ body {background: #EEEEEE; margin: 0; padding: 0;
65
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode',
66
+ 'Garuda';}
67
+ code {font-family: 'Lucida Console', monospace;
68
+ font-size: 12px;}
69
+ li {height: 18px;}
70
+ ul {list-style: none; margin: 0; padding: 0;}
71
+ ol:hover {cursor: pointer;}
72
+ ol li {white-space: pre;}
73
+ #explanation {font-size: 12px; color: #666666;
74
+ margin: 20px 0 0 100px;}
75
+ /* WRAP */
76
+ #wrap {width: 1000px; background: #FFFFFF; margin: 0 auto;
77
+ padding: 30px 50px 20px 50px;
78
+ border-left: 1px solid #DDDDDD;
79
+ border-right: 1px solid #DDDDDD;}
80
+ /* HEADER */
81
+ #header {margin: 0 auto 25px auto;}
82
+ #header img {float: left;}
83
+ #header #summary {float: left; margin: 12px 0 0 20px; width:660px;
84
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode';}
85
+ h1 {margin: 0; font-size: 36px; color: #981919;}
86
+ h2 {margin: 0; font-size: 22px; color: #333333;}
87
+ #header ul {margin: 0; font-size: 12px; color: #666666;}
88
+ #header ul li strong{color: #444444;}
89
+ #header ul li {display: inline; padding: 0 10px;}
90
+ #header ul li.first {padding-left: 0;}
91
+ #header ul li.last {border: 0; padding-right: 0;}
92
+ /* BODY */
93
+ #backtrace,
94
+ #get,
95
+ #post,
96
+ #cookies,
97
+ #rack {width: 980px; margin: 0 auto 10px auto;}
98
+ p#nav {float: right; font-size: 14px;}
99
+ /* BACKTRACE */
100
+ a#expando {float: left; padding-left: 5px; color: #666666;
101
+ font-size: 14px; text-decoration: none; cursor: pointer;}
102
+ a#expando:hover {text-decoration: underline;}
103
+ h3 {float: left; width: 100px; margin-bottom: 10px;
104
+ color: #981919; font-size: 14px; font-weight: bold;}
105
+ #nav a {color: #666666; text-decoration: none; padding: 0 5px;}
106
+ #backtrace li.frame-info {background: #f7f7f7; padding-left: 10px;
107
+ font-size: 12px; color: #333333;}
108
+ #backtrace ul {list-style-position: outside; border: 1px solid #E9E9E9;
109
+ border-bottom: 0;}
110
+ #backtrace ol {width: 920px; margin-left: 50px;
111
+ font: 10px 'Lucida Console', monospace; color: #666666;}
112
+ #backtrace ol li {border: 0; border-left: 1px solid #E9E9E9;
113
+ padding: 2px 0;}
114
+ #backtrace ol code {font-size: 10px; color: #555555; padding-left: 5px;}
115
+ #backtrace-ul li {border-bottom: 1px solid #E9E9E9; height: auto;
116
+ padding: 3px 0;}
117
+ #backtrace-ul .code {padding: 6px 0 4px 0;}
118
+ #backtrace.condensed .system,
119
+ #backtrace.condensed .framework {display:none;}
120
+ /* REQUEST DATA */
121
+ p.no-data {padding-top: 2px; font-size: 12px; color: #666666;}
122
+ table.req {width: 980px; text-align: left; font-size: 12px;
123
+ color: #666666; padding: 0; border-spacing: 0;
124
+ border: 1px solid #EEEEEE; border-bottom: 0;
125
+ border-left: 0;
126
+ clear:both}
127
+ table.req tr th {padding: 2px 10px; font-weight: bold;
128
+ background: #F7F7F7; border-bottom: 1px solid #EEEEEE;
129
+ border-left: 1px solid #EEEEEE;}
130
+ table.req tr td {padding: 2px 20px 2px 10px;
131
+ border-bottom: 1px solid #EEEEEE;
132
+ border-left: 1px solid #EEEEEE;}
133
+ /* HIDE PRE/POST CODE AT START */
134
+ .pre-context,
135
+ .post-context {display: none;}
136
+
137
+ table td.code {width:750px}
138
+ table td.code div {width:750px;overflow:hidden}
139
+ </style>
140
+ </head>
141
+ <body>
142
+ <div id="wrap">
143
+ <div id="header">
144
+ <img src="/__sinatra__/500.png" alt="application error" height="161" width="313" />
145
+ <div id="summary">
146
+ <h1><strong><%=h exception.class %></strong> at <strong><%=h path %>
147
+ </strong></h1>
148
+ <h2><%=h exception.message %></h2>
149
+ <ul>
150
+ <li class="first"><strong>file:</strong> <code>
151
+ <%=h frames.first.filename.split("/").last %></code></li>
152
+ <li><strong>location:</strong> <code><%=h frames.first.function %>
153
+ </code></li>
154
+ <li class="last"><strong>line:
155
+ </strong> <%=h frames.first.lineno %></li>
156
+ </ul>
157
+ </div>
158
+ <div class="clear"></div>
159
+ </div>
160
+
161
+ <div id="backtrace" class='condensed'>
162
+ <h3>BACKTRACE</h3>
163
+ <p><a href="#" id="expando"
164
+ onclick="toggleBacktrace(); return false">(expand)</a></p>
165
+ <p id="nav"><strong>JUMP TO:</strong>
166
+ <a href="#get-info">GET</a>
167
+ <a href="#post-info">POST</a>
168
+ <a href="#cookie-info">COOKIES</a>
169
+ <a href="#env-info">ENV</a>
170
+ </p>
171
+ <div class="clear"></div>
172
+
173
+ <ul id="backtrace-ul">
174
+
175
+ <% id = 1 %>
176
+ <% frames.each do |frame| %>
177
+ <% if frame.context_line && frame.context_line != "#" %>
178
+
179
+ <li class="frame-info <%= frame_class(frame) %>">
180
+ <code><%=h frame.filename %></code> in
181
+ <code><strong><%=h frame.function %></strong></code>
182
+ </li>
183
+
184
+ <li class="code <%= frame_class(frame) %>">
185
+ <% if frame.pre_context %>
186
+ <ol start="<%=h frame.pre_context_lineno + 1 %>"
187
+ class="pre-context" id="pre-<%= id %>"
188
+ onclick="toggle(<%= id %>);">
189
+ <% frame.pre_context.each do |line| %>
190
+ <li class="pre-context-line"><code><%=h line %></code></li>
191
+ <% end %>
192
+ </ol>
193
+ <% end %>
194
+
195
+ <ol start="<%= frame.lineno %>" class="context" id="<%= id %>"
196
+ onclick="toggle(<%= id %>);">
197
+ <li class="context-line" id="context-<%= id %>"><code><%=
198
+ h frame.context_line %></code></li>
199
+ </ol>
200
+
201
+ <% if frame.post_context %>
202
+ <ol start="<%=h frame.lineno + 1 %>" class="post-context"
203
+ id="post-<%= id %>" onclick="toggle(<%= id %>);">
204
+ <% frame.post_context.each do |line| %>
205
+ <li class="post-context-line"><code><%=h line %></code></li>
206
+ <% end %>
207
+ </ol>
208
+ <% end %>
209
+ <div class="clear"></div>
210
+ </li>
211
+
212
+ <% end %>
213
+
214
+ <% id += 1 %>
215
+ <% end %>
216
+
217
+ </ul>
218
+ </div> <!-- /BACKTRACE -->
219
+
220
+ <div id="get">
221
+ <h3 id="get-info">GET</h3>
222
+ <% unless req.GET.empty? %>
223
+ <table class="req">
224
+ <tr>
225
+ <th>Variable</th>
226
+ <th>Value</th>
227
+ </tr>
228
+ <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %>
229
+ <tr>
230
+ <td><%=h key %></td>
231
+ <td class="code"><div><%=h val.inspect %></div></td>
232
+ </tr>
233
+ <% } %>
234
+ </table>
235
+ <% else %>
236
+ <p class="no-data">No GET data.</p>
237
+ <% end %>
238
+ <div class="clear"></div>
239
+ </div> <!-- /GET -->
240
+
241
+ <div id="post">
242
+ <h3 id="post-info">POST</h3>
243
+ <% unless req.POST.empty? %>
244
+ <table class="req">
245
+ <tr>
246
+ <th>Variable</th>
247
+ <th>Value</th>
248
+ </tr>
249
+ <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %>
250
+ <tr>
251
+ <td><%=h key %></td>
252
+ <td class="code"><div><%=h val.inspect %></div></td>
253
+ </tr>
254
+ <% } %>
255
+ </table>
256
+ <% else %>
257
+ <p class="no-data">No POST data.</p>
258
+ <% end %>
259
+ <div class="clear"></div>
260
+ </div> <!-- /POST -->
261
+
262
+ <div id="cookies">
263
+ <h3 id="cookie-info">COOKIES</h3>
264
+ <% unless req.cookies.empty? %>
265
+ <table class="req">
266
+ <tr>
267
+ <th>Variable</th>
268
+ <th>Value</th>
269
+ </tr>
270
+ <% req.cookies.each { |key, val| %>
271
+ <tr>
272
+ <td><%=h key %></td>
273
+ <td class="code"><div><%=h val.inspect %></div></td>
274
+ </tr>
275
+ <% } %>
276
+ </table>
277
+ <% else %>
278
+ <p class="no-data">No cookie data.</p>
279
+ <% end %>
280
+ <div class="clear"></div>
281
+ </div> <!-- /COOKIES -->
282
+
283
+ <div id="rack">
284
+ <h3 id="env-info">Rack ENV</h3>
285
+ <table class="req">
286
+ <tr>
287
+ <th>Variable</th>
288
+ <th>Value</th>
289
+ </tr>
290
+ <% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
291
+ <tr>
292
+ <td><%=h key %></td>
293
+ <td class="code"><div><%=h val %></div></td>
294
+ </tr>
295
+ <% } %>
296
+ </table>
297
+ <div class="clear"></div>
298
+ </div> <!-- /RACK ENV -->
299
+
300
+ <p id="explanation">You're seeing this error because you have
301
+ enabled the <code>show_exceptions</code> setting.</p>
302
+ </div> <!-- /WRAP -->
303
+ </body>
304
+ </html>
305
+ HTML
306
+ end
307
+ end
@@ -0,0 +1,62 @@
1
+ require 'thread'
2
+ require 'time'
3
+ require 'uri'
4
+ # require 'addressable/uri'
5
+ require 'rack'
6
+ require 'rack/builder'
7
+
8
+ module Crystal
9
+ # The request object. See Rack::Request for more info:
10
+ # http://rack.rubyforge.org/doc/classes/Rack/Request.html
11
+ class Request < Rack::Request
12
+ # Returns an array of acceptable media types for the response
13
+ def accept
14
+ @env['HTTP_ACCEPT'].to_s.split(',').map { |a| a.split(';')[0].strip }
15
+ end
16
+
17
+ def secure?
18
+ (@env['HTTP_X_FORWARDED_PROTO'] || @env['rack.url_scheme']) == 'https'
19
+ end
20
+
21
+ # Override Rack < 1.1's Request#params implementation (see lh #72 for
22
+ # more info) and add a Request#user_agent method.
23
+ # XXX remove when we require rack > 1.1
24
+ if Rack.release < '1.1'
25
+ def params
26
+ self.GET.update(self.POST)
27
+ rescue EOFError, Errno::ESPIPE
28
+ self.GET
29
+ end
30
+
31
+ def user_agent
32
+ @env['HTTP_USER_AGENT']
33
+ end
34
+ end
35
+ end
36
+
37
+ # The response object. See Rack::Response and Rack::ResponseHelpers for
38
+ # more info:
39
+ # http://rack.rubyforge.org/doc/classes/Rack/Response.html
40
+ # http://rack.rubyforge.org/doc/classes/Rack/Response/Helpers.html
41
+ class Response < Rack::Response
42
+ def finish
43
+ @body = block if block_given?
44
+ if [204, 304].include?(status.to_i)
45
+ header.delete "Content-Type"
46
+ [status.to_i, header.to_hash, []]
47
+ else
48
+ body = @body || []
49
+ body = [body] if body.respond_to? :to_str
50
+ if body.respond_to?(:to_ary)
51
+ header["Content-Length"] = body.to_ary.
52
+ inject(0) { |len, part| len + Rack::Utils.bytesize(part) }.to_s
53
+ end
54
+ [status.to_i, header.to_hash, body]
55
+ end
56
+ end
57
+ end
58
+
59
+ class NotFound < NameError #:nodoc:
60
+ def code ; 404 ; end
61
+ end
62
+ end
@@ -0,0 +1 @@
1
+ - Use Rack::Utils for escape
@@ -0,0 +1,5 @@
1
+ module Crystal
2
+ module Remote
3
+
4
+ end
5
+ end
@@ -0,0 +1,40 @@
1
+ module Crystal
2
+ class Setting
3
+ attr_accessor :host, :port, :environment, :server, :session, :static
4
+ %w{session show_exceptions static}.each do |m|
5
+ iv = "@#{m}"
6
+ define_method("#{m}?"){!!instance_variable_get(iv)}
7
+ end
8
+
9
+ def initialize
10
+ {
11
+ :host => '0.0.0.0',
12
+ :port => 4000,
13
+ :environment => 'development',
14
+ :server => 'Mongrel',
15
+ :session => true,
16
+ :static => true
17
+ }.each{|k, v| self.send "#{k}=", v if self.send(k).nil?}
18
+ end
19
+
20
+ def development?; environment == 'development' end
21
+ def production?; environment == 'production' end
22
+ def test?; environment == 'test' end
23
+
24
+ def apply_command_line_arguments!
25
+ require 'optparse'
26
+
27
+ case ARGV.first
28
+ when "p" then self.environment = "production"
29
+ when "d" then self.environment = "development"
30
+ when "t" then self.environment = "test"
31
+ end
32
+
33
+ OptionParser.new{|op|
34
+ op.on('-e env'){|val| self.environment = val}
35
+ op.on('-s server'){|val| self.server = val}
36
+ op.on('-p port'){|val| self.port = val.to_i}
37
+ }.parse!(ARGV.dup)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ gem 'activeresource', '= 2.3.5'
2
+
3
+ # autoload :BacktraceCleaner, 'active_support/backtrace_cleaner'
4
+ autoload :Base64, 'active_support/base64'
5
+ autoload :BasicObject, 'active_support/basic_object'
6
+ # autoload :BufferedLogger, 'active_support/buffered_logger'
7
+ # autoload :Cache, 'active_support/cache'
8
+ # autoload :Callbacks, 'active_support/callbacks'
9
+ # autoload :Deprecation, 'active_support/deprecation'
10
+ # autoload :Duration, 'active_support/duration'
11
+ # autoload :Gzip, 'active_support/gzip'
12
+ autoload :Inflector, 'active_support/inflector'
13
+ # autoload :Memoizable, 'active_support/memoizable'
14
+ # autoload :MessageEncryptor, 'active_support/message_encryptor'
15
+ # autoload :MessageVerifier, 'active_support/message_verifier'
16
+ # autoload :Multibyte, 'active_support/multibyte'
17
+ # autoload :OptionMerger, 'active_support/option_merger'
18
+ # autoload :OrderedHash, 'active_support/ordered_hash'
19
+ # autoload :OrderedOptions, 'active_support/ordered_options'
20
+ # autoload :Rescuable, 'active_support/rescuable'
21
+ # autoload :SecureRandom, 'active_support/secure_random'
22
+ # autoload :StringInquirer, 'active_support/string_inquirer'
23
+ autoload :TimeWithZone, 'active_support/time_with_zone'
24
+ autoload :TimeZone, 'active_support/values/time_zone'
25
+ # autoload :XmlMini, 'active_support/xml_mini'
26
+
27
+ # require 'active_support/vendor'
28
+ require 'active_support/core_ext'
29
+ # require 'active_support/dependencies'
30
+ require 'active_support/json'
@@ -0,0 +1,130 @@
1
+ attr_reader :template_cache
2
+
3
+ def initialize(app=nil)
4
+ @app = app
5
+ @template_cache = Tilt::Cache.new
6
+ yield self if block_given?
7
+ end
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+ # Template rendering methods. Each method takes the name of a template
34
+ # to render as a Symbol and returns a String with the rendered output,
35
+ # as well as an optional hash with additional options.
36
+ #
37
+ # `template` is either the name or path of the template as symbol
38
+ # (Use `:'subdir/myview'` for views in subdirectories), or a string
39
+ # that will be rendered.
40
+ #
41
+ # Possible options are:
42
+ # :layout If set to false, no layout is rendered, otherwise
43
+ # the specified layout is used (Ignored for `sass` and `less`)
44
+ # :locals A hash with local variables that should be available
45
+ # in the template
46
+ module Templates
47
+ include Tilt::CompileSite
48
+
49
+ def erb(template, options={}, locals={})
50
+ options[:outvar] = '@_out_buf'
51
+ render :erb, template, options, locals
52
+ end
53
+
54
+ def erubis(template, options={}, locals={})
55
+ options[:outvar] = '@_out_buf'
56
+ render :erubis, template, options, locals
57
+ end
58
+
59
+ def haml(template, options={}, locals={})
60
+ render :haml, template, options, locals
61
+ end
62
+
63
+ def sass(template, options={}, locals={})
64
+ options[:layout] = false
65
+ render :sass, template, options, locals
66
+ end
67
+
68
+ def less(template, options={}, locals={})
69
+ options[:layout] = false
70
+ render :less, template, options, locals
71
+ end
72
+
73
+ def builder(template=nil, options={}, locals={}, &block)
74
+ options, template = template, nil if template.is_a?(Hash)
75
+ template = Proc.new { block } if template.nil?
76
+ render :builder, template, options, locals
77
+ end
78
+
79
+ private
80
+ def render(engine, data, options={}, locals={}, &block)
81
+ # merge app-level options
82
+ options = settings.send(engine).merge(options) if settings.respond_to?(engine)
83
+
84
+ # extract generic options
85
+ locals = options.delete(:locals) || locals || {}
86
+ views = options.delete(:views) || settings.views || "./views"
87
+ layout = options.delete(:layout)
88
+ layout = :layout if layout.nil? || layout == true
89
+
90
+ # compile and render template
91
+ template = compile_template(engine, data, options, views)
92
+ output = template.render(self, locals, &block)
93
+
94
+ # render layout
95
+ if layout
96
+ begin
97
+ options = options.merge(:views => views, :layout => false)
98
+ output = render(engine, layout, options, locals) { output }
99
+ rescue Errno::ENOENT
100
+ end
101
+ end
102
+
103
+ output
104
+ end
105
+
106
+ def compile_template(engine, data, options, views)
107
+ template_cache.fetch engine, data, options do
108
+ template = Tilt[engine]
109
+ raise "Template engine not found: #{engine}" if template.nil?
110
+
111
+ case
112
+ when data.is_a?(Symbol)
113
+ body, path, line = self.class.templates[data]
114
+ if body
115
+ body = body.call if body.respond_to?(:call)
116
+ template.new(path, line.to_i, options) { body }
117
+ else
118
+ path = ::File.join(views, "#{data}.#{engine}")
119
+ template.new(path, 1, options)
120
+ end
121
+ when data.is_a?(Proc) || data.is_a?(String)
122
+ body = data.is_a?(String) ? Proc.new { data } : data
123
+ path, line = self.class.caller_locations.first
124
+ template.new(path, line.to_i, options, &body)
125
+ else
126
+ raise ArgumentError
127
+ end
128
+ end
129
+ end
130
+ end
@@ -4,7 +4,12 @@ require 'spec/rake/spectask'
4
4
  Dir.chdir File.dirname(__FILE__)
5
5
 
6
6
  # Specs
7
- task :default => :spec
7
+ # task :default => :spec
8
+
9
+ task :default => :tst
10
+ task :tst do
11
+ p :hello
12
+ end
8
13
 
9
14
  Spec::Rake::SpecTask.new('spec') do |t|
10
15
  t.spec_files = FileList["spec/**/*_spec.rb"]
@@ -18,19 +23,19 @@ require 'fileutils'
18
23
 
19
24
  spec = Gem::Specification.new do |s|
20
25
  s.name = "crystal"
21
- s.version = "0.0.1"
22
- s.summary = "The Crystal Web Framework"
23
- s.description = "The Crystal Web Framework"
26
+ s.version = "0.0.2"
27
+ s.summary = "Crystal - Ruby Web Framework"
28
+ s.description = "Crystal - Ruby Web Framework"
24
29
  s.author = "Alexey Petrushin"
25
30
  # s.email = ""
26
- s.homepage = "http://www.bos-tec.com"
31
+ s.homepage = "http://github.com/alexeypetrushin/crystal"
27
32
  # s.rubyforge_project = "RubyExt"
28
33
 
29
34
  s.platform = Gem::Platform::RUBY
30
- s.has_rdoc = true
31
- s.extra_rdoc_files = ["README.rdoc"]
35
+ s.has_rdoc = true
36
+ # s.extra_rdoc_files = ["README.rdoc"]
32
37
 
33
- s.files = (%w{Rakefile README.rdoc} + Dir.glob("{lib,spec}/**/*"))
38
+ s.files = (%w{rakefile readme.md .gitignore} + Dir.glob("{lib,spec,.git}/**/*"))
34
39
  # s.executables = ['restclient']
35
40
  # s.add_dependency("BlueCloth", ">= 0.0.4")
36
41
  # s.add_dependency "facets"
@@ -52,7 +57,7 @@ end
52
57
 
53
58
  task :push do
54
59
  dir = Dir.chdir PACKAGE_DIR do
55
- gem_file = Dir.glob("ruby-ext*.gem").first
60
+ gem_file = Dir.glob("crystal*.gem").first
56
61
  system "gem push #{gem_file}"
57
62
  end
58
63
  end
data/readme.md ADDED
@@ -0,0 +1,4 @@
1
+ # Crystal - Ruby Web Framework.
2
+
3
+ It's a code extracted from my [http://bom4.com](http://bom4.com) application.
4
+ It's under heavy development now and not ready for use.
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crystal
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alexey Petrushin
@@ -15,24 +15,95 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-05-27 00:00:00 +04:00
18
+ date: 2010-06-05 00:00:00 +04:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
22
- description: The Crystal Web Framework
22
+ description: Crystal - Ruby Web Framework
23
23
  email:
24
24
  executables: []
25
25
 
26
26
  extensions: []
27
27
 
28
- extra_rdoc_files:
29
- - README.rdoc
28
+ extra_rdoc_files: []
29
+
30
30
  files:
31
- - Rakefile
32
- - README.rdoc
33
- - spec/spec.opts
31
+ - rakefile
32
+ - readme.md
33
+ - .gitignore
34
+ - lib/crystal/core.rb
35
+ - lib/crystal/garbage.rb
36
+ - lib/crystal/helpers.rb
37
+ - lib/crystal/rack/adapter.rb
38
+ - lib/crystal/rack/middleware/static_files.rb
39
+ - lib/crystal/rack/rack_app.rb
40
+ - lib/crystal/rack/showexceptions.rb
41
+ - lib/crystal/rack/support.rb
42
+ - lib/crystal/readme.txt
43
+ - lib/crystal/remote.rb
44
+ - lib/crystal/setting.rb
45
+ - lib/crystal/support/active_support.rb
46
+ - lib/crystal/template.rb
47
+ - .git/COMMIT_EDITMSG
48
+ - .git/config
49
+ - .git/description
50
+ - .git/HEAD
51
+ - .git/hooks/applypatch-msg.sample
52
+ - .git/hooks/commit-msg.sample
53
+ - .git/hooks/post-commit.sample
54
+ - .git/hooks/post-receive.sample
55
+ - .git/hooks/post-update.sample
56
+ - .git/hooks/pre-applypatch.sample
57
+ - .git/hooks/pre-commit.sample
58
+ - .git/hooks/pre-rebase.sample
59
+ - .git/hooks/prepare-commit-msg.sample
60
+ - .git/hooks/update.sample
61
+ - .git/index
62
+ - .git/info/exclude
63
+ - .git/logs/HEAD
64
+ - .git/logs/refs/heads/master
65
+ - .git/logs/refs/remotes/origin/master
66
+ - .git/objects/00/c26dc781c8997ed2bfa61f03b323466a3860d1
67
+ - .git/objects/04/03ee94b34a5760c46616cd13c317e69cb90d56
68
+ - .git/objects/09/66c6b45bacaae9282463b9b4c0ce8488bbcee5
69
+ - .git/objects/0d/03131f9fbc3e2fb1f8f9b616ac273d05f3a7f5
70
+ - .git/objects/0e/50f691a65b41ba9e7df9d6738ff9f333089b34
71
+ - .git/objects/14/6253750089fd522535155630344c8ff2a60830
72
+ - .git/objects/15/f5669d470665c6bd28b5ab7b65431e199c36e9
73
+ - .git/objects/28/a3d1b3c79d0e59b8359ecd75e4ec0d62f60468
74
+ - .git/objects/2c/b339709e1fb005a3e3006e76558d2e45333008
75
+ - .git/objects/2d/077a401db466ea0b1f062eac15293879293439
76
+ - .git/objects/38/3af6cb155addf818eb9396229892743112dbc3
77
+ - .git/objects/42/828defbc95389daf9bfa11c8b2341f98303ee7
78
+ - .git/objects/44/b6d8df4e1f924caeb7de56135c251ce24998fd
79
+ - .git/objects/46/42a59703e31a105aa67c4511be5e41402d08af
80
+ - .git/objects/56/43b861a644b727a8b54ae003977151d975f360
81
+ - .git/objects/5e/11ba5e0794a914747bae95b942b2dbeb5c36c3
82
+ - .git/objects/5f/2b8b8c9f16877c91fda9a177e235698103c4c9
83
+ - .git/objects/63/82b66d637e3d04e78a6272e25d3e212de90a10
84
+ - .git/objects/66/aa791f24ea2ed8717abe3d1c74da4ad544723d
85
+ - .git/objects/68/02f5c496f00787242a9fa1a81eb9847071e076
86
+ - .git/objects/81/031da1db90c4cd43fe27336054d76564dbe64c
87
+ - .git/objects/86/738c97b0d7ac8443a25cbcd0c4e147bcdb152e
88
+ - .git/objects/8d/a995e65577a82011df060b13a498f0a738d017
89
+ - .git/objects/90/cfb8df76866f20a0c9c4adfb6d5d1faebad9d3
90
+ - .git/objects/a9/38b272a1a743d7e30caa05b5513760195ec0a8
91
+ - .git/objects/b1/244bb3652d56ebe4b465468e214d1a1fa87ebb
92
+ - .git/objects/b4/e715329ba853104d19112487b1188571bca659
93
+ - .git/objects/bf/1e07cd3085bed5be7f3ca1860ec8c14d0fdebb
94
+ - .git/objects/c5/ef2f6ac4ee5779fa79f7afb54a458191352e86
95
+ - .git/objects/cc/0b74e32ae045d3208839aa91d0dc94f5ea4c09
96
+ - .git/objects/d8/53eba81fc4b75fbc90cf8c39f4b1344deddc9f
97
+ - .git/objects/df/e23416f16c0bb6c98ca2a0b1d02d803ff53831
98
+ - .git/objects/df/ee793cf3fd89820e5a9a4481d35000d75040d9
99
+ - .git/objects/e0/f7b971a634e34d7976676a4d575c654746a5f8
100
+ - .git/objects/f3/8245046bfe9c478a502c58b1c1434f382800d3
101
+ - .git/objects/f6/3c2e6d83a07cf107ff63a6b92a72a0ac5e9e3f
102
+ - .git/objects/fc/794047fc246572581a7fdce016e1be6b8ab61a
103
+ - .git/refs/heads/master
104
+ - .git/refs/remotes/origin/master
34
105
  has_rdoc: true
35
- homepage: http://www.bos-tec.com
106
+ homepage: http://github.com/alexeypetrushin/crystal
36
107
  licenses: []
37
108
 
38
109
  post_install_message:
@@ -64,6 +135,6 @@ rubyforge_project:
64
135
  rubygems_version: 1.3.7
65
136
  signing_key:
66
137
  specification_version: 3
67
- summary: The Crystal Web Framework
138
+ summary: Crystal - Ruby Web Framework
68
139
  test_files: []
69
140
 
data/README.rdoc DELETED
@@ -1 +0,0 @@
1
- Web Framework, not releaset yet.
data/spec/spec.opts DELETED
@@ -1,3 +0,0 @@
1
- --color
2
- --reverse
3
- --backtrace