crystal 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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