freddie 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.yardopt ADDED
@@ -0,0 +1 @@
1
+ --no-private --protected lib/**/*.rb - README LEGAL COPYING
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in freddie.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Hendrik Mans
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Freddie
2
+
3
+ Yet another web application framework for Ruby. :)
4
+
5
+ ## Example
6
+
7
+ ```
8
+ run Freddie do
9
+ layout 'application.html.haml'
10
+
11
+ # Serve some asset files
12
+ #
13
+ path('application-:timestamp.css') { stylesheet 'application.scss' }
14
+ path('application-:timestamp.js') { javascript 'application.js' }
15
+
16
+ # Built-in OmniAuth support
17
+ #
18
+ omni_auth
19
+
20
+ # Provide a /logout action
21
+ #
22
+ path('logout') do
23
+ session['omniauth_user'] = nil
24
+ redirect_to '/'
25
+ end
26
+
27
+ # Mount a RESTful resource. This adds all the required
28
+ # paths and even applies authorization scopes for the
29
+ # currently logged in user.
30
+ #
31
+ resource :events do
32
+ can :index, :show
33
+ can :new, :create, :update, :destroy if current_user.admin?
34
+ end
35
+
36
+ # The root action is a simple redirect.
37
+ #
38
+ redirect_to '/events'
39
+ end
40
+ ```
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new do |t|
6
+ t.pattern = "spec/*_spec.rb"
7
+ end
8
+
9
+ task :default => :test
data/freddie.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/freddie/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Hendrik Mans"]
6
+ gem.email = ["hendrik@mans.de"]
7
+ gem.description = %q{Expressive, Rack-loving web application DSL.}
8
+ gem.summary = %q{Expressive, Rack-loving web application DSL.}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "freddie"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Freddie::VERSION
17
+
18
+ gem.add_dependency 'rack', '~> 1.4.1'
19
+ gem.add_dependency 'activesupport', '~> 3.2.3'
20
+ gem.add_dependency 'tilt', '~> 1.3.3'
21
+
22
+ gem.add_development_dependency 'rack-test'
23
+ gem.add_development_dependency 'minitest-reporters'
24
+ end
@@ -0,0 +1,13 @@
1
+ module Freddie
2
+ class Application < Handlers::Base
3
+ class << self
4
+ def block=(block)
5
+ @@block = block
6
+ end
7
+ end
8
+
9
+ def perform
10
+ instance_exec &@@block if @@block
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module Freddie
2
+ class Context
3
+ attr_accessor :request, :response, :params, :path
4
+
5
+ def initialize(env)
6
+ @request = Rack::Request.new(env)
7
+ @response = Rack::Response.new
8
+ @params = @request.params.with_indifferent_access
9
+ @path = @request.path.gsub(/^\//, '').split('/')
10
+ @finished = false
11
+ end
12
+
13
+ def current_user
14
+ session['omniauth_user'].try(:last)
15
+ end
16
+
17
+ def session
18
+ request.session
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,223 @@
1
+ module Freddie
2
+ module Handlers
3
+
4
+ # Base class for all handlers.
5
+ #
6
+ class Base
7
+ attr_reader :block, :env
8
+
9
+ class << self
10
+ def call(env)
11
+ new.call(env)
12
+ end
13
+ end
14
+
15
+ def initialize(*args, &block)
16
+ @args = args
17
+ @block = block
18
+ end
19
+
20
+ def call(env)
21
+ @env = env
22
+ before_perform
23
+ perform(*@args)
24
+ after_perform
25
+ response
26
+ end
27
+
28
+ def before_perform ; end
29
+ def perform(*args) ; end
30
+ def after_perform ; end
31
+
32
+ def context
33
+ env['freddie.context'] ||= Context.new(env)
34
+ end
35
+
36
+ def response
37
+ context.response
38
+ end
39
+
40
+ def request
41
+ context.request
42
+ end
43
+
44
+ def params
45
+ context.params
46
+ end
47
+
48
+ def session
49
+ context.request.session
50
+ end
51
+
52
+ def layout(name)
53
+ env['freddie.layout'] = name
54
+ end
55
+
56
+ def finish!
57
+ env['freddie.finished'] = true
58
+ end
59
+
60
+ def finished?
61
+ env['freddie.finished']
62
+ end
63
+
64
+ def method_missing(name, *args, &block)
65
+ klass_name = "Freddie::Handlers::#{name.to_s.classify}"
66
+
67
+ unless finished?
68
+ klass = klass_name.constantize or raise MissingHandlerError, "Could not locate #{klass_name}"
69
+ klass.new(*args, &block).tap do |handler|
70
+ handler.call(env)
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ module Endpoint
77
+ def before_perform
78
+ raise NotFoundError if context.path.any?
79
+ end
80
+
81
+ def after_perform
82
+ finish!
83
+ end
84
+ end
85
+
86
+ class Path < Base
87
+ def perform(path)
88
+ if match_data = self.class.path_to_regexp(path).match(context.path.first)
89
+ # write parameter matches into params
90
+ match_data.names.each { |k| params[k] = match_data[k] }
91
+
92
+ # execute block
93
+ el = context.path.shift
94
+
95
+ if block
96
+ # cater for different DSL styles
97
+ if block.arity == 1
98
+ block.call(self)
99
+ else
100
+ instance_exec &block
101
+ end
102
+ end
103
+
104
+ context.path.unshift(el)
105
+ end
106
+ end
107
+
108
+ class << self
109
+ def path_to_regexp(path)
110
+ path = ":#{path}" if path.is_a?(Symbol)
111
+ Regexp.compile('^'+path.gsub(/\)/, ')?').gsub(/\//, '\/').gsub(/\./, '\.').gsub(/:(\w+)/, '(?<\\1>\w+)')+'$')
112
+ end
113
+ end
114
+ end
115
+
116
+ class Render < Base
117
+ include Endpoint
118
+
119
+ def perform(data)
120
+ response.body << data
121
+ end
122
+ end
123
+
124
+ class Template < Base
125
+ include Endpoint
126
+
127
+ def perform(name, variables = {})
128
+ html = Tilt.new("views/%s" % name).render(self, variables)
129
+ if env['freddie.layout'].present?
130
+ html = Tilt.new("views/#{env['freddie.layout']}").render(self) { html }
131
+ end
132
+ response.body << html
133
+ end
134
+ end
135
+
136
+ class Resource < Base
137
+ def perform(name, options = {})
138
+ options = {
139
+ name: name.to_s,
140
+ singular_name: name.to_s.singularize,
141
+ plural_name: name.to_s.pluralize,
142
+ klass: name.to_s.classify.constantize
143
+ }.merge(options)
144
+
145
+ path(options[:name]) do |n|
146
+ n.path(:id) do |n|
147
+ n.template "#{options[:plural_name]}/show.html.haml",
148
+ options[:singular_name] => options[:klass].find(params[:id])
149
+ end
150
+
151
+ n.template "#{options[:plural_name]}/index.html.haml",
152
+ options[:plural_name] => options[:klass].all
153
+ end
154
+ end
155
+ end
156
+
157
+ class RedirectTo < Base
158
+ include Endpoint
159
+
160
+ def perform(destination)
161
+ response.headers['Location'] = destination
162
+ response.status = 302
163
+ end
164
+ end
165
+
166
+ class Run < Base
167
+ include Endpoint
168
+
169
+ def perform(app)
170
+ context.response = Rack::Response.new(app.call(env))
171
+ end
172
+ end
173
+
174
+ class Stylesheet < Base
175
+ include Endpoint
176
+
177
+ def perform(name)
178
+ response.headers['Content-type'] = 'text/css'
179
+ layout nil
180
+ template name
181
+ end
182
+ end
183
+
184
+ class SendFile < Base
185
+ include Endpoint
186
+
187
+ def perform(name)
188
+ response.body << File.read(name)
189
+ end
190
+ end
191
+
192
+ class Javascript < Base
193
+ include Endpoint
194
+
195
+ def perform(name)
196
+ response.headers['Content-type'] = 'text/javascript'
197
+
198
+ # insert crazy javascript packing code here... :)
199
+ response.body << File.read("views/#{name}")
200
+ end
201
+ end
202
+
203
+ class OmniAuth < Base
204
+ def perform(options = {})
205
+ options = {
206
+ session_key: :omniauth_user,
207
+ redirect_to: '/'
208
+ }.merge(options)
209
+
210
+ path('auth') do
211
+ path(:provider) do
212
+ path('callback') do
213
+ auth = env['omniauth.auth']
214
+ session[options[:session_key]] = [auth['provider'], auth['uid']]
215
+ redirect_to options[:redirect_to]
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+
222
+ end
223
+ end
@@ -0,0 +1,3 @@
1
+ module Freddie
2
+ VERSION = "0.0.1"
3
+ end
data/lib/freddie.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'active_support/core_ext/hash'
2
+ require 'rack'
3
+ require 'tilt'
4
+
5
+ require 'freddie/version'
6
+ require 'freddie/context'
7
+ require 'freddie/handlers'
8
+ require 'freddie/application'
9
+
10
+ module Freddie
11
+ class FreddieError < StandardError ; end
12
+ class NotFoundError < FreddieError ; end
13
+ class MissingHandlerError < FreddieError ; end
14
+ end
15
+
16
+ def Freddie(&block)
17
+ app = Class.new(Freddie::Application)
18
+ app.block = block
19
+ app
20
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'spec_helper'
2
+
3
+ include Rack::Test::Methods
4
+
5
+ describe Freddie::Handlers::Render do
6
+ def app ; Freddie::Handlers::Render.new('moo') ; end
7
+
8
+ before { get '/' }
9
+
10
+ it "should add content to the response body" do
11
+ last_response.body.must_equal 'moo'
12
+ end
13
+ end
14
+
@@ -0,0 +1,55 @@
1
+ require_relative 'spec_helper'
2
+
3
+ include Rack::Test::Methods
4
+
5
+ describe "integration" do
6
+ def app
7
+ Freddie do
8
+ path('foo') { render 'bar' }
9
+ path('one') { path('two') { path('three') { render '123' }}}
10
+ path('hello') { path(:name) { render "hello %s" % params[:name] }}
11
+ path('rack') { run SillyLittleRackApp.new }
12
+
13
+ render 'root'
14
+
15
+ path('should_never_work') { render 'strange' }
16
+ end
17
+ end
18
+
19
+ class SillyLittleRackApp
20
+ def call(env)
21
+ Rack::Response.new.tap do |r|
22
+ r.body << "I'm a silly little Rack app"
23
+ end
24
+ end
25
+ end
26
+
27
+ it "can serve something at the root level" do
28
+ get '/'
29
+ last_response.body.must_equal 'root'
30
+ end
31
+
32
+ it "can handle paths" do
33
+ get '/foo'
34
+ last_response.body.must_equal 'bar'
35
+ end
36
+
37
+ it "can handle paths within paths" do
38
+ get '/one/two/three'
39
+ last_response.body.must_equal '123'
40
+ end
41
+
42
+ it "support path variables" do
43
+ get '/hello/hendrik'
44
+ last_response.body.must_equal 'hello hendrik'
45
+ end
46
+
47
+ it "supports mounting of Rack apps" do
48
+ get '/rack'
49
+ last_response.body.must_equal "I'm a silly little Rack app"
50
+ end
51
+
52
+ it "halts processing after rendering" do
53
+ lambda { get '/should_never_work' }.must_raise Freddie::NotFoundError
54
+ end
55
+ end
@@ -0,0 +1,9 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+ require 'minitest/reporters'
4
+ require 'rack/test'
5
+
6
+ MiniTest::Unit.runner = MiniTest::SuiteRunner.new
7
+ MiniTest::Unit.runner.reporters << MiniTest::Reporters::ProgressReporter.new
8
+
9
+ require 'freddie'
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: freddie
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Hendrik Mans
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: &70194826049540 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70194826049540
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &70194826048660 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 3.2.3
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70194826048660
36
+ - !ruby/object:Gem::Dependency
37
+ name: tilt
38
+ requirement: &70194826047820 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.3.3
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70194826047820
47
+ - !ruby/object:Gem::Dependency
48
+ name: rack-test
49
+ requirement: &70194826047100 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70194826047100
58
+ - !ruby/object:Gem::Dependency
59
+ name: minitest-reporters
60
+ requirement: &70194826046180 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70194826046180
69
+ description: Expressive, Rack-loving web application DSL.
70
+ email:
71
+ - hendrik@mans.de
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - .yardopt
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - freddie.gemspec
83
+ - lib/freddie.rb
84
+ - lib/freddie/application.rb
85
+ - lib/freddie/context.rb
86
+ - lib/freddie/handlers.rb
87
+ - lib/freddie/version.rb
88
+ - spec/handlers_spec.rb
89
+ - spec/integration_spec.rb
90
+ - spec/spec_helper.rb
91
+ homepage: ''
92
+ licenses: []
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 1.8.11
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: Expressive, Rack-loving web application DSL.
115
+ test_files:
116
+ - spec/handlers_spec.rb
117
+ - spec/integration_spec.rb
118
+ - spec/spec_helper.rb
119
+ has_rdoc: