otto 0.2.1.003 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,10 @@
1
1
  OTTO, CHANGES
2
2
 
3
+ #### 0.3.0 (2011-12-17) ###############################
4
+
5
+ * ADDED: Example app, better docs in readme
6
+ * CHANGE: No default value for user agent
7
+
3
8
  #### 0.2.1 (2011-07-07) ###############################
4
9
 
5
10
  * ADDED: Otto#add_static_path
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Delano Mandelbaum
1
+ Copyright (c) 2011,2012 Delano Mandelbaum
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,8 +1,112 @@
1
1
  # Otto - 0.2
2
2
 
3
- **Auto-define your rack-apps in plaintext.**
3
+ **Auto-define your rack-apps in plain-text.**
4
+
5
+ ## Overview ##
6
+
7
+ Apps build with Otto have three, basic parts: a rackup file, a ruby file, and a routes file. If you've built a [Rack app](http://rack.rubyforge.org/) before, then you've seen a rackup file before. The ruby file is your actual app and the routes file is what Otto uses to map URI paths to a Ruby method.
4
8
 
9
+ A barebones app directory looks something like this:
5
10
 
11
+ $ cd myapp
12
+ $ ls
13
+ config.ru app.rb routes
14
+
15
+ See the examples/ directory for a working app.
16
+
17
+
18
+ ### Routes ###
19
+
20
+ The routes file is just a plain-text file which defines the end points of your application. Each route has three parts:
21
+
22
+ * HTTP verb (GET, POST, PUT, DELETE or HEAD)
23
+ * URI path
24
+ * Ruby class and method to call
25
+
26
+ Here is an example:
27
+
28
+ GET / App#index
29
+ POST / App#receive_feedback
30
+ GET /redirect App#redirect
31
+ GET /robots.txt App#robots_text
32
+ GET /product/:prodid App#display_product
33
+
34
+ # You can also define these handlers when no
35
+ # route can be found or there's a server error. (optional)
36
+ GET /404 App#not_found
37
+ GET /500 App#server_error
38
+
39
+ ### App ###
40
+
41
+ There is nothing special about the Ruby class. The only requirement is that the first two arguments to initialize be a Rack::Request object and a Rack::Response object. Otherwise, you can do anything you want. You're free to use any templating engine, any database mapper, etc. There is no magic.
42
+
43
+ class App
44
+ attr_reader :req, :res
45
+
46
+ # Otto creates an instance of this class for every request
47
+ # and passess the Rack::Request and Rack::Response objects.
48
+ def initialize req, res
49
+ @req, @res = req, res
50
+ end
51
+
52
+ def index
53
+ res.header['Content-Type'] = "text/html; charset=utf-8"
54
+ lines = [
55
+ '<img src="/img/otto.jpg" /><br/><br/>',
56
+ 'Send feedback:<br/>',
57
+ '<form method="post"><input name="msg" /><input type="submit" /></form>',
58
+ '<a href="/product/100">A product example</a>'
59
+ ]
60
+ res.body = lines.join($/)
61
+ end
62
+
63
+ def receive_feedback
64
+ res.body = req.params.inspect
65
+ end
66
+
67
+ def redirect
68
+ res.redirect '/robots.txt'
69
+ end
70
+
71
+ def robots_text
72
+ res.header['Content-Type'] = "text/plain"
73
+ rules = 'User-agent: *', 'Disallow: /private'
74
+ res.body = rules.join($/)
75
+ end
76
+
77
+ def display_product
78
+ res.header['Content-Type'] = "application/json; charset=utf-8"
79
+ prodid = req.params[:prodid]
80
+ res.body = '{"product":%s,"msg":"Hint: try another value"}' % [prodid]
81
+ end
82
+
83
+ def not_found
84
+ res.status = 404
85
+ res.body = "Item not found!"
86
+ end
87
+
88
+ def server_error
89
+ res.status = 500
90
+ res.body = "There was a server error!"
91
+ end
92
+ end
93
+
94
+ ### Rackup ###
95
+
96
+ There is also nothing special about the rackup file. It just builds a Rack app using your routes file.
97
+
98
+ require 'otto'
99
+ require 'app'
100
+
101
+ app = Otto.new("./routes")
102
+
103
+ map('/') {
104
+ run app
105
+ }
106
+
107
+ See the examples/ directory for a working app.
108
+
109
+
6
110
  ## Installation
7
111
 
8
112
  Get it in one of the following ways:
@@ -14,23 +118,28 @@ Get it in one of the following ways:
14
118
  You can also download via [tarball](http://github.com/delano/otto/tarball/latest) or [zip](http://github.com/delano/otto/zipball/latest).
15
119
 
16
120
 
17
-
18
121
  ## More Information
19
122
 
20
123
  * [Codes](http://github.com/delano/otto)
21
124
  * [RDocs](http://solutious.com/otto)
22
125
 
23
126
 
24
- ## Credits
127
+ ## In the wild ##
25
128
 
26
- * [Delano Mandelbaum](http://solutious.com)
129
+ Services that use Otto:
130
+
131
+ * [One-Time Secret](https://onetimesecret.com/) -- A safe way to share sensitive data.
132
+ * [BlameStella](https://www.blamestella.com/) -- Web monitoring for devs and designers.
27
133
 
28
134
 
29
- ## Thanks
135
+ ## Credits
136
+
137
+ * [Delano Mandelbaum](http://solutious.com)
30
138
 
31
139
 
32
140
  ## Related Projects
33
141
 
142
+ * [Sinatra](http://www.sinatrarb.com/)
34
143
 
35
144
  ## License
36
145
 
data/Rakefile CHANGED
@@ -3,11 +3,7 @@ require "rake"
3
3
  require "rake/clean"
4
4
  require 'yaml'
5
5
 
6
- begin
7
- require 'hanna/rdoctask'
8
- rescue LoadError
9
- require 'rake/rdoctask'
10
- end
6
+ require 'hanna/rdoctask'
11
7
 
12
8
  config = YAML.load_file("VERSION.yml")
13
9
  task :default => ["build"]
@@ -17,7 +13,7 @@ name = "otto"
17
13
  begin
18
14
  require "jeweler"
19
15
  Jeweler::Tasks.new do |gem|
20
- gem.version = "#{config[:MAJOR]}.#{config[:MINOR]}.#{config[:PATCH]}.#{config[:BUILD]}"
16
+ gem.version = "#{config[:MAJOR]}.#{config[:MINOR]}.#{config[:PATCH]}"
21
17
  gem.name = "otto"
22
18
  gem.rubyforge_project = gem.name
23
19
  gem.summary = "Auto-define your rack-apps in plaintext."
@@ -35,7 +31,7 @@ end
35
31
 
36
32
 
37
33
  Rake::RDocTask.new do |rdoc|
38
- version = "#{config[:MAJOR]}.#{config[:MINOR]}.#{config[:PATCH]}.#{config[:BUILD]}"
34
+ version = "#{config[:MAJOR]}.#{config[:MINOR]}.#{config[:PATCH]}"
39
35
  rdoc.rdoc_dir = "doc"
40
36
  rdoc.title = "otto #{version}"
41
37
  rdoc.rdoc_files.include("README*")
@@ -1,4 +1,3 @@
1
1
  :MAJOR: 0
2
- :MINOR: 2
3
- :PATCH: 1
4
- :BUILD: '003'
2
+ :MINOR: 3
3
+ :PATCH: 0
@@ -0,0 +1,57 @@
1
+
2
+
3
+ class App
4
+
5
+ # An instance of Rack::Request
6
+ attr_reader :req
7
+ # An instance of Rack::Response
8
+ attr_reader :res
9
+
10
+ # Otto creates an instance of this class for every request
11
+ # and passess the Rack::Request and Rack::Response objects.
12
+ def initialize req, res
13
+ @req, @res = req, res
14
+ res.header['Content-Type'] = "text/html; charset=utf-8"
15
+ end
16
+
17
+ def index
18
+ lines = [
19
+ '<img src="/img/otto.jpg" /><br/><br/>',
20
+ 'Send feedback:<br/>',
21
+ '<form method="post"><input name="msg" /><input type="submit" /></form>',
22
+ '<a href="/product/100">A product example</a>'
23
+ ]
24
+ res.body = lines.join($/)
25
+ end
26
+
27
+ def receive_feedback
28
+ res.body = req.params.inspect
29
+ end
30
+
31
+ def redirect
32
+ res.redirect '/robots.txt'
33
+ end
34
+
35
+ def robots_text
36
+ res.header['Content-Type'] = "text/plain"
37
+ rules = 'User-agent: *', 'Disallow: /private'
38
+ res.body = rules.join($/)
39
+ end
40
+
41
+ def display_product
42
+ res.header['Content-Type'] = "application/json; charset=utf-8"
43
+ prodid = req.params[:prodid]
44
+ res.body = '{"product":%s,"msg":"Hint: try another value"}' % [prodid]
45
+ end
46
+
47
+ def not_found
48
+ res.status = 404
49
+ res.body = "Item not found!"
50
+ end
51
+
52
+ def server_error
53
+ res.status = 500
54
+ res.body = "There was a server error!"
55
+ end
56
+
57
+ end
@@ -0,0 +1,35 @@
1
+ # OTTO EXAMPLE APP CONFIG - 2011-12-17
2
+ #
3
+ # Usage:
4
+ #
5
+ # $ thin -e dev -R config.ru -p 10770 start
6
+ # $ tail -f /var/log/system.log
7
+
8
+ ENV['RACK_ENV'] ||= 'prod'
9
+ ENV['APP_ROOT'] = ::File.expand_path(::File.join(::File.dirname(__FILE__)))
10
+ $:.unshift(::File.join(ENV['APP_ROOT']))
11
+ $:.unshift(::File.join(ENV['APP_ROOT'], '..', 'lib'))
12
+
13
+ require 'otto'
14
+ require 'app'
15
+
16
+ PUBLIC_DIR = "#{ENV['APP_ROOT']}/public"
17
+ APP_DIR = "#{ENV['APP_ROOT']}"
18
+
19
+ app = Otto.new("#{APP_DIR}/routes")
20
+
21
+ if Otto.env?(:dev) # DEV: Run web apps with extra logging and reloading
22
+ map('/') {
23
+ use Rack::CommonLogger
24
+ use Rack::Reloader, 0
25
+ app.option[:public] = PUBLIC_DIR
26
+ app.add_static_path '/favicon.ico'
27
+ run app
28
+ }
29
+ # Specify static paths to serve in dev-mode only
30
+ map('/etc/') { run Rack::File.new("#{PUBLIC_DIR}/etc") }
31
+ map('/img/') { run Rack::File.new("#{PUBLIC_DIR}/img") }
32
+
33
+ else # PROD: run barebones webapp
34
+ map('/') { run app }
35
+ end
@@ -0,0 +1,17 @@
1
+ # OTTO - ROUTES EXAMPLE
2
+
3
+ # Each route has three parts:
4
+ # * HTTP verb (GET, POST, PUT, DELETE or HEAD)
5
+ # * URI path
6
+ # * Ruby class and method to call
7
+
8
+ GET / App#index
9
+ POST / App#receive_feedback
10
+ GET /redirect App#redirect
11
+ GET /robots.txt App#robots_text
12
+ GET /product/:prodid App#display_product
13
+
14
+ # You can also define these handlers when no
15
+ # route can be found or there's a server error. (optional)
16
+ GET /404 App#not_found
17
+ GET /500 App#server_error
@@ -13,8 +13,7 @@ class Otto
13
13
  [@version[:MAJOR], @version[:MINOR], @version[:PATCH]].join('.')
14
14
  end
15
15
  def self.inspect
16
- load_config
17
- [@version[:MAJOR], @version[:MINOR], @version[:PATCH], @version[:BUILD]].join('.')
16
+ to_s
18
17
  end
19
18
  def self.load_config
20
19
  require 'yaml'
@@ -320,9 +319,8 @@ class Otto
320
319
  end
321
320
  module RequestHelpers
322
321
  def user_agent
323
- env['HTTP_USER_AGENT'] || '[no-user-agent]'
322
+ env['HTTP_USER_AGENT']
324
323
  end
325
-
326
324
  # HTTP_X_FORWARDED_FOR is from the ELB (non-https only)
327
325
  # and it can take the form: 74.121.244.2, 10.252.130.147
328
326
  # HTTP_X_REAL_IP is from nginx
@@ -332,62 +330,49 @@ class Otto
332
330
  env['HTTP_X_FORWARDED_FOR'].to_s.split(/,\s*/).first ||
333
331
  env['HTTP_X_REAL_IP'] || env['REMOTE_ADDR']
334
332
  end
335
-
336
333
  def request_method
337
334
  env['REQUEST_METHOD']
338
335
  end
339
-
340
336
  def current_server
341
337
  [current_server_name, env['SERVER_PORT']].join(':')
342
338
  end
343
-
344
339
  def current_server_name
345
340
  env['SERVER_NAME']
346
341
  end
347
-
348
342
  def http_host
349
343
  env['HTTP_HOST']
350
344
  end
351
345
  def request_path
352
346
  env['REQUEST_PATH']
353
347
  end
354
-
355
348
  def request_uri
356
349
  env['REQUEST_URI']
357
350
  end
358
-
359
351
  def root_path
360
352
  env['SCRIPT_NAME']
361
353
  end
362
-
363
354
  def absolute_suri host=current_server_name
364
355
  prefix = local? ? 'http://' : 'https://'
365
356
  [prefix, host, request_path].join
366
357
  end
367
-
368
358
  def local?
369
359
  Otto.env?(:dev, :development) && client_ipaddress == '127.0.0.1'
370
360
  end
371
-
372
361
  def secure?
373
362
  # X-Scheme is set by nginx
374
363
  # X-FORWARDED-PROTO is set by elastic load balancer
375
364
  (env['HTTP_X_FORWARDED_PROTO'] == 'https' || env['HTTP_X_SCHEME'] == "https")
376
365
  end
377
-
378
366
  def cookie name
379
367
  cookies[name.to_s]
380
368
  end
381
-
382
369
  def cookie? name
383
370
  !cookie(name).to_s.empty?
384
371
  end
385
-
386
372
  def current_absolute_uri
387
373
  prefix = secure? && !local? ? 'https://' : 'http://'
388
374
  [prefix, http_host, request_path].join
389
375
  end
390
-
391
376
  end
392
377
  module ResponseHelpers
393
378
  attr_accessor :request
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "otto"
8
- s.version = "0.2.1.003"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Delano Mandelbaum"]
12
- s.date = "2011-10-19"
12
+ s.date = "2011-12-20"
13
13
  s.description = "Auto-define your rack-apps in plaintext."
14
14
  s.email = "delano@solutious.com"
15
15
  s.extra_rdoc_files = [
@@ -22,6 +22,11 @@ Gem::Specification.new do |s|
22
22
  "README.md",
23
23
  "Rakefile",
24
24
  "VERSION.yml",
25
+ "example/app.rb",
26
+ "example/config.ru",
27
+ "example/public/favicon.ico",
28
+ "example/public/img/otto.jpg",
29
+ "example/routes",
25
30
  "lib/otto.rb",
26
31
  "otto.gemspec"
27
32
  ]
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: otto
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.1.003
5
+ version: 0.3.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Delano Mandelbaum
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-10-19 00:00:00 Z
13
+ date: 2011-12-20 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -49,6 +49,11 @@ files:
49
49
  - README.md
50
50
  - Rakefile
51
51
  - VERSION.yml
52
+ - example/app.rb
53
+ - example/config.ru
54
+ - example/public/favicon.ico
55
+ - example/public/img/otto.jpg
56
+ - example/routes
52
57
  - lib/otto.rb
53
58
  - otto.gemspec
54
59
  homepage: http://github.com/delano/otto