lego-core 0.0.1

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
+ coverage
2
+ doc
3
+ tmp/**/*
data/README.rdoc ADDED
@@ -0,0 +1,95 @@
1
+ = Lego-core
2
+
3
+ It's all about the bits an pieces!
4
+
5
+ == Installation
6
+
7
+ sudo gem install lego-core
8
+
9
+ == TODO
10
+
11
+ - Write a text that describe what we are trying to do, and why :)
12
+ - Write a roadmap for lego-core
13
+ - Add before and after filter handling.
14
+
15
+ == Example plugin (plugin.rb)
16
+
17
+ # This is a sample plugin that extends a few different Lego contexts.
18
+ #
19
+ # - View plugin
20
+ # - Controller plugin
21
+ # - Route matcher plugin
22
+ #
23
+ # This code will prob. be held in a different gem
24
+
25
+ module SamplePlugin
26
+
27
+ # Register is called by lego when plugin is loaded
28
+
29
+ def self.register(lego)
30
+ lego.add_plugin :view, View
31
+ lego.add_plugin :router, Matcher
32
+ lego.add_plugin :controller, Routes
33
+ end
34
+
35
+ # A plugin module we load as a view helper
36
+
37
+ module View
38
+ def h1(content)
39
+ "<h1>#{content}</h1>"
40
+ end
41
+ end
42
+
43
+ # A very simply route helper
44
+
45
+ module Routes
46
+ def get(path, &block)
47
+ add_route(:get, {:path => path, :action_block => block})
48
+ end
49
+ end
50
+
51
+ # A very simple route matcher
52
+
53
+ module Matcher
54
+ def self.match_route(route, env)
55
+ (route[:path] == env['PATH_INFO']) ? true : false
56
+ end
57
+ end
58
+ end
59
+
60
+ == Example Lego Application (my_app.rb)
61
+
62
+ # This is how our Lego app would look with this plugin.
63
+
64
+ Lego.plugin SamplePlugin
65
+
66
+ class MyApp < Lego::Controller
67
+ get '/hello' do
68
+ h1 'Hello world'
69
+ end
70
+ end
71
+
72
+ == Example Rackup/Shotgun file (config.ru)
73
+
74
+ # This is how you would use it with rack.
75
+
76
+ require 'rubygems'
77
+ require 'lego-core'
78
+ require 'plugin'
79
+ require 'my_app'
80
+
81
+ run MyApp
82
+
83
+ == Example run
84
+
85
+ # Start this app by running shotgun or rackup (these gems nees to be installed)
86
+
87
+ shotgun config.ru
88
+
89
+ == Thoughts
90
+
91
+ - Move ActionContext and RouteHandler into different module that controller?
92
+ - Add a plugin Context for before and after filters to make them pluggable?
93
+ - Make the whole framework run inside an instance instead of as class methods?
94
+ - When route is matchen with a different method than the one requested you should not respond 404, support for this?
95
+
data/Rakefile ADDED
@@ -0,0 +1,63 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+ require 'rcov/rcovtask'
4
+
5
+
6
+ begin
7
+ require 'spec/rake/spectask'
8
+ rescue LoadError
9
+ puts 'To use rspec for testing you must install rspec gem:'
10
+ puts '$ sudo gem install rspec'
11
+ exit
12
+ end
13
+
14
+ desc "Default task is to run specs"
15
+ task :default => :show_all_tasks
16
+
17
+ desc "Run all examples with RCov"
18
+ Spec::Rake::SpecTask.new('rcov') do |t|
19
+ t.spec_files = FileList['spec/**/*.rb']
20
+ t.spec_opts = ['--options', '"spec/spec.opts"']
21
+ # rcov
22
+ t.rcov = true
23
+ t.rcov_dir = 'doc/coverage'
24
+ t.rcov_opts = ['-p', '-T', '--exclude', 'spec']
25
+ end
26
+
27
+ desc "Run the specs under spec"
28
+ Spec::Rake::SpecTask.new do |t|
29
+ t.spec_opts = ['--diff', '--options', "spec/spec.opts"]
30
+ t.spec_files = FileList['spec/**/*_spec.rb']
31
+ end
32
+
33
+ desc "Print Specdoc for all specs"
34
+ Spec::Rake::SpecTask.new('specdoc') do |t|
35
+ t.spec_opts = ["--format", "specdoc", "--dry-run", "--options", 'spec/spec.opts']
36
+ t.spec_files = FileList['spec/**/*_spec.rb']
37
+ end
38
+
39
+ desc "Generate RDoc documentation"
40
+ Rake::RDocTask.new(:rdoc) do |rdoc|
41
+ rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc' << '--charset' << 'utf-8'
42
+ rdoc.rdoc_dir = "doc"
43
+ rdoc.rdoc_files.include 'README.rdoc'
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
46
+
47
+ begin
48
+ require 'jeweler'
49
+ Jeweler::Tasks.new do |gemspec|
50
+ gemspec.name = "lego-core"
51
+ gemspec.summary = "It's all about the bits and peices"
52
+ gemspec.description = "It's all about the bits and peices"
53
+ gemspec.email = "mathias@globalinn.com"
54
+ gemspec.homepage = "http://github.com/stjernstrom/lego-core"
55
+ gemspec.authors = ["Mathias Stjernström", "Patrik Hedman"]
56
+ end
57
+ rescue LoadError
58
+ puts "Jeweler not available. Install it with: gem install jeweler"
59
+ end
60
+
61
+ task :show_all_tasks do
62
+ system "rake -T"
63
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,137 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib', 'lego')
2
+
3
+ module BasicRoutes
4
+ def self.register(lego)
5
+ lego.add_plugin :controller, ControllerPlugin
6
+ lego.add_plugin :router, RouteMatcher
7
+ end
8
+
9
+ module ControllerPlugin
10
+ def get(path, &block)
11
+ add_route(:get, { :path => path, :action_block => block })
12
+ end
13
+ end
14
+
15
+ module RouteMatcher
16
+ def self.match_route(route, env)
17
+ (route[:path] == env['PATH_INFO']) ? true : false
18
+ end
19
+ end
20
+ end
21
+
22
+ module RegexpMatcher
23
+ def self.register(lego)
24
+ lego.add_plugin :router, self
25
+ end
26
+
27
+ def self.match_route(route, env)
28
+ if route[:path].is_a?(Regexp) && match = route[:path].match(env['PATH_INFO'])
29
+ route[:instance_vars] = { :caps => match.captures }
30
+ true
31
+ else
32
+ false
33
+ end
34
+ end
35
+ end
36
+
37
+ module SymbolExtractor
38
+ def self.register(lego)
39
+ lego.add_plugin :router, self
40
+ end
41
+
42
+ def self.match_route(route, env)
43
+ return false if not route[:path].kind_of?(String)
44
+ matches = route[:path].scan(/:([\w]+)/)
45
+ if matches.size > 0
46
+ exp = Regexp.escape( route[:path] ).gsub(/:([\w]+)/, "([\\w]+)")
47
+ if match = Regexp.new("^#{exp}$").match(env["PATH_INFO"])
48
+ route[:instance_vars] = {} if route[:instance_vars].nil?
49
+ 1.upto(matches.size) do |i|
50
+ route[:instance_vars][matches[i-1]] = match.captures[i-1]
51
+ end
52
+ return true
53
+ end
54
+ end
55
+ false
56
+ end
57
+ end
58
+
59
+ module HtmlPlug
60
+ def self.register(lego)
61
+ lego.add_plugin :view, Mod
62
+ end
63
+ module Mod
64
+ def h1(content)
65
+ "<h1>#{content}</h1>"
66
+ end
67
+ def b(content)
68
+ "<b>#{content}</b>"
69
+ end
70
+ end
71
+ end
72
+
73
+ class MyBlog < Lego::Controller
74
+ set :foo => "bar"
75
+
76
+ plugin BasicRoutes
77
+ plugin RegexpMatcher
78
+ plugin SymbolExtractor
79
+
80
+ # Sample ActionContext plugin giving h1() and b() methods to views.
81
+ plugin HtmlPlug
82
+
83
+ #
84
+ # Ex: http://localhost:9393/extract/something.jpg
85
+ # Sets up an instance variable with the matches
86
+ # @caps[0] => 'something'
87
+ # @caps[1] => 'jpg'
88
+ #
89
+ get /extract\/(\w+)\.(\w+)/ do
90
+ "We are extracting....#{@caps.inspect}"
91
+ end
92
+
93
+ #
94
+ # Ex: http://localhost:9393/
95
+ #
96
+ get '/' do
97
+ "This is /"
98
+ end
99
+
100
+ #
101
+ # ex: http://localhost:9393/show/10
102
+ # Sets up an instance variable with the id
103
+ # @id => 10
104
+ #
105
+ get '/show/:id' do
106
+ "This is show with id = #{@id}"
107
+ end
108
+
109
+ get '/options' do
110
+ options :foo # renders bar to the browser
111
+ end
112
+
113
+ #
114
+ # Demonstrating a simple ActionContext plugin (HtmlPlug)
115
+ #
116
+ # Ex: http://localhost:9393/viewplugins
117
+ #
118
+ get '/viewplugins' do
119
+ h1("Hello, i'm a header.") + b("And im some stupid bold text.....")
120
+ end
121
+
122
+ #
123
+ # This action will be called if no other route matches.
124
+ #
125
+ # Ex: http://localhost:9393/you_will_not_find_me/
126
+ #
127
+ not_found do
128
+ h1("404 - File not found") + "Lego could not find what you are looking for, sorry."
129
+ end
130
+
131
+
132
+ end
133
+
134
+ run MyBlog
135
+
136
+ # Save this stuff to config.ru and fire it up with 'rackup'
137
+
data/lego-core.gemspec ADDED
@@ -0,0 +1,70 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{lego-core}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Mathias Stjernstr\303\266m", "Patrik Hedman"]
12
+ s.date = %q{2010-01-12}
13
+ s.description = %q{It's all about the bits and peices}
14
+ s.email = %q{mathias@globalinn.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "examples/config.ru",
24
+ "lego-core.gemspec",
25
+ "lib/lego.rb",
26
+ "lib/lego/controller.rb",
27
+ "lib/lego/controller/action_context.rb",
28
+ "lib/lego/controller/config.rb",
29
+ "lib/lego/controller/route_handler.rb",
30
+ "lib/lego/plugin.rb",
31
+ "lib/lego/plugin/controller/not_found.rb",
32
+ "spec/integration/test_full_stack_spec.rb",
33
+ "spec/lego/controller/action_context_spec.rb",
34
+ "spec/lego/controller/config_spec.rb",
35
+ "spec/lego/controller/route_handler_spec.rb",
36
+ "spec/lego/controller_spec.rb",
37
+ "spec/lego/plugin/controller/not_found_spec.rb",
38
+ "spec/lego/plugin_spec.rb",
39
+ "spec/lego_spec.rb",
40
+ "spec/spec.opts",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/stjernstrom/lego-core}
44
+ s.rdoc_options = ["--charset=UTF-8"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.3.5}
47
+ s.summary = %q{It's all about the bits and peices}
48
+ s.test_files = [
49
+ "spec/integration/test_full_stack_spec.rb",
50
+ "spec/lego/controller/action_context_spec.rb",
51
+ "spec/lego/controller/config_spec.rb",
52
+ "spec/lego/controller/route_handler_spec.rb",
53
+ "spec/lego/controller_spec.rb",
54
+ "spec/lego/plugin/controller/not_found_spec.rb",
55
+ "spec/lego/plugin_spec.rb",
56
+ "spec/lego_spec.rb",
57
+ "spec/spec_helper.rb"
58
+ ]
59
+
60
+ if s.respond_to? :specification_version then
61
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
62
+ s.specification_version = 3
63
+
64
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
65
+ else
66
+ end
67
+ else
68
+ end
69
+ end
70
+
data/lib/lego.rb ADDED
@@ -0,0 +1,38 @@
1
+ #
2
+ #:title:Lego-Core
3
+ #
4
+
5
+ module Lego
6
+
7
+ file_path = File.expand_path( File.dirname(__FILE__) )
8
+ $LOAD_PATH.unshift( file_path ) unless $LOAD_PATH.include?( file_path )
9
+
10
+ VERSION = [0,0,1]
11
+
12
+ #
13
+ # Return the current Lego version.
14
+ #
15
+
16
+ def self.version
17
+ VERSION.join(".")
18
+ end
19
+
20
+ autoload :Controller, 'lego/controller'
21
+ autoload :Plugin, 'lego/plugin'
22
+
23
+ def self.config(&block)
24
+ class_eval &block
25
+ end
26
+
27
+ #
28
+ # plugin lets a plugin register itself globally
29
+ #
30
+
31
+ def self.plugin(plugin_module)
32
+ plugin_module.register(Lego::Controller)
33
+ end
34
+
35
+ def self.set(options={})
36
+ Lego::Controller.set options
37
+ end
38
+ end
@@ -0,0 +1,162 @@
1
+ #
2
+ # = Lego::Controller
3
+ # Lego::Controller is the context where you setup routes and stuff.
4
+ #
5
+
6
+ class Lego::Controller
7
+
8
+ autoload :ActionContext, 'lego/controller/action_context'
9
+ autoload :RouteHandler, 'lego/controller/route_handler'
10
+ autoload :Config, 'lego/controller/config'
11
+
12
+ class << self
13
+
14
+ #
15
+ # When Lego::Controller is inherited it will create a new Lego::Controller::ActionContext for the class thats inheriting
16
+ # and it will also create a new Lego::Controller::RouteHandler module for the class thats inheriting.
17
+ #
18
+
19
+ def inherited(class_inheriting)
20
+ class_inheriting.const_set(:ActionContext, Class.new(Lego::Controller::ActionContext) do
21
+ const_set :ApplicationClass, class_inheriting
22
+ end)
23
+
24
+ class_inheriting.const_set(:RouteHandler, Module.new { extend Lego::Controller::RouteHandler })
25
+ class_inheriting.const_set(:Config, Module.new { extend Lego::Controller::Config })
26
+ end
27
+
28
+ #
29
+ # Use register inside your plugin to inject your code into the right place.
30
+ #
31
+ # Context available are:
32
+ #
33
+ # - :controller
34
+ # - :router
35
+ # - :view
36
+ #
37
+ # and on the way
38
+ #
39
+ # - :helper ?
40
+ #
41
+
42
+ def add_plugin(context, plugin_module)
43
+
44
+ base = (self == Lego::Controller) ? Lego::Controller : self
45
+
46
+ case context
47
+ when :controller
48
+ base.extend plugin_module
49
+ when :router
50
+ base::RouteHandler.add_matcher plugin_module
51
+ when :view
52
+ base::ActionContext.instance_eval do
53
+ include plugin_module
54
+ end
55
+ end
56
+ end
57
+
58
+ #
59
+ # add_route <method> <route> is exposed to your plugin as a shortcut for adding routes to the application they are plugged in to.
60
+ #
61
+ # <method> is a symbol for the request method it should match
62
+ #
63
+ # Valid options are:
64
+ #
65
+ # - :get
66
+ # - :post
67
+ # - :put
68
+ # - :head
69
+ # - :options
70
+ # - :not_found
71
+ #
72
+ # <route> is a hash with keys to be handled by the route matchers and also the ActionContext
73
+ #
74
+ # Valid options are anything your route matcher can handle. But there's some keys that's special for Lego and they are.
75
+ #
76
+ # - :action_block => A block thats going to be executed inside ActionContext.
77
+ # - :instance_vars => A hash where the keys beeing converted to ActionContext vars ex: { :var1 => "value1", :var2 => "value2" }
78
+ # - :set_response_code => An integer representing the response code.
79
+ #
80
+
81
+ def add_route(method, route)
82
+ self::RouteHandler.add_route(method, route)
83
+ end
84
+
85
+ #
86
+ # Use plugin in your controllers to choose which extensions you want to use in this controller.
87
+ #
88
+ # Extensions then inject themself into the right context.
89
+ #
90
+
91
+ def plugin(plugin_module)
92
+ plugin_module.register(self)
93
+ end
94
+
95
+ #
96
+ # Provides acces to the current Config class
97
+ #
98
+
99
+ def current_config
100
+ self::Config
101
+ end
102
+
103
+ #
104
+ # Use set to define environment agnostic configuration options
105
+ #
106
+ # Usage:
107
+ # Lego::Controller.set :foo => "bar"
108
+ #
109
+
110
+ def set(options={})
111
+ current_config.set(options)
112
+ end
113
+
114
+ #
115
+ # Use environment to define environment specific configuration options
116
+ #
117
+ # Usage:
118
+ # Lego::Controller.environment :development do
119
+ # set :foo => "bar"
120
+ # end
121
+ #
122
+ # or set environment agnostic configuration options by leaving out the environment parameter
123
+ #
124
+ # Usage:
125
+ # Lego::Controller.environment do
126
+ # set :foo => "bar"
127
+ # end
128
+ #
129
+
130
+ def environment(env=nil, &block)
131
+ raise ArgumentError, "No block provided" unless block_given?
132
+ current_config.environment(env, &block)
133
+ end
134
+
135
+ #
136
+ # call is used to handle an incomming Rack request.
137
+ #
138
+ # If no matching route is found we check for a defined :not_found route
139
+ # and if no :not_found defined we send a simple 404 - not found.
140
+ #
141
+
142
+ def call(env)
143
+ if route = self::RouteHandler.match_all_routes(env)
144
+ self::ActionContext.new.run(route, env)
145
+ else
146
+ if route = self::RouteHandler.routes[:not_found]
147
+ self::ActionContext.new.run(route, env)
148
+ else
149
+ [404, {'Content-Type' => 'text/html'}, '404 - Not found']
150
+ end
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+ #
157
+ # Core plugins
158
+ #
159
+
160
+ plugin Lego::Plugin::Controller::NotFound
161
+
162
+ end