sansom 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/changelog.md +30 -0
- data/examples/before.rb +20 -0
- data/examples/generic.rb +2 -1
- data/lib/sansom/pine.rb +118 -0
- data/lib/sansom.rb +43 -71
- data/sansom.gemspec +14 -16
- metadata +7 -18
- data/lib/sansom/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83d66dba113385fce6c56f322029124339fd7b95
|
4
|
+
data.tar.gz: b8bd60af145d70fa86659611cbb68cfc7b406377
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 848745905809706be2a7fe194f017249053296ddd858b6f380425ed9d5c89bd92eab1049c9b33b4a00b7cf943d311d2ea6ffce33e1efb641dca4c26518495fda
|
7
|
+
data.tar.gz: 566b2bf914317d9c64df03cef8518be605d7b26835bf10602f0883ce960ec62ccc45072434d177acdebcb411c2e55f77a5f3ba2efc9ff719af9de46cdc5a436a
|
data/changelog.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Changelog
|
2
|
+
=
|
3
|
+
|
4
|
+
0.0.1
|
5
|
+
|
6
|
+
(yanked due to bad name in Gemfile)
|
7
|
+
|
8
|
+
0.0.2
|
9
|
+
|
10
|
+
- Initial release
|
11
|
+
|
12
|
+
0.0.3
|
13
|
+
|
14
|
+
- Wrote custom tree implementation called Pine to replace RubyTree
|
15
|
+
- Added `before` block
|
16
|
+
|
17
|
+
Here's an example
|
18
|
+
|
19
|
+
s = Sansom.new
|
20
|
+
|
21
|
+
s.before do |r|
|
22
|
+
# Caveat: routes are mapped before this block is called
|
23
|
+
# Code executed before mapped route
|
24
|
+
end
|
25
|
+
|
26
|
+
s.get "/" do |r|
|
27
|
+
[200, {}, ["Hello!"]]
|
28
|
+
end
|
29
|
+
|
30
|
+
s.start 2000
|
data/examples/before.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../lib/sansom"
|
4
|
+
|
5
|
+
s = Sansom.new
|
6
|
+
|
7
|
+
s.before do |r|
|
8
|
+
puts "(#{s.class.to_s}) #{r.request_method.upcase} #{r.path_info}"
|
9
|
+
[200, {}, ["Hijacked by before!"]] if Random.new.rand(2) == 1
|
10
|
+
end
|
11
|
+
|
12
|
+
s.get "/" do |r|
|
13
|
+
[200, { "Content-Type" => "text/plain"}, ["root"]]
|
14
|
+
end
|
15
|
+
|
16
|
+
s.get "/something" do |r|
|
17
|
+
[200, { "Content-Type" => "text/plain" }, ["something"]]
|
18
|
+
end
|
19
|
+
|
20
|
+
s.start 2000
|
data/examples/generic.rb
CHANGED
data/lib/sansom/pine.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Path routing tree
|
4
|
+
|
5
|
+
# Custom tree implementation for path routing
|
6
|
+
|
7
|
+
# Custom features:
|
8
|
+
# 1. Trimming: Limit a node to a single element
|
9
|
+
|
10
|
+
module Pine
|
11
|
+
class Node
|
12
|
+
attr_reader :name
|
13
|
+
attr_accessor :content
|
14
|
+
attr_accessor :parent
|
15
|
+
|
16
|
+
def initialize name, content=Content.new
|
17
|
+
@name = name
|
18
|
+
@content = content
|
19
|
+
@children = {}
|
20
|
+
@parent = nil
|
21
|
+
@trimmed = false
|
22
|
+
end
|
23
|
+
|
24
|
+
# returns a node for chaining
|
25
|
+
def <<(node)
|
26
|
+
if trimmed?
|
27
|
+
# Add to first child
|
28
|
+
children.first << node
|
29
|
+
else
|
30
|
+
node.parent = self
|
31
|
+
@children[node.name] = node
|
32
|
+
node
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_if_necessary name
|
37
|
+
unless @children.keys.include? name
|
38
|
+
child = self.class.new name
|
39
|
+
child.parent = self
|
40
|
+
@children[name] = child
|
41
|
+
end
|
42
|
+
@children[name]
|
43
|
+
end
|
44
|
+
|
45
|
+
def root
|
46
|
+
n = self
|
47
|
+
n = n.parent while !n.root?
|
48
|
+
n
|
49
|
+
end
|
50
|
+
|
51
|
+
def children
|
52
|
+
@children.values
|
53
|
+
end
|
54
|
+
|
55
|
+
def trim(node)
|
56
|
+
@trimmed = true
|
57
|
+
@children.clear
|
58
|
+
@children[node.name] = node
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def []=(k,v)
|
63
|
+
self << Node.new(k, v)
|
64
|
+
end
|
65
|
+
|
66
|
+
def [](k)
|
67
|
+
@children[k]
|
68
|
+
end
|
69
|
+
|
70
|
+
def root?
|
71
|
+
@parent.nil?
|
72
|
+
end
|
73
|
+
|
74
|
+
def leaf?
|
75
|
+
@children.count == 0
|
76
|
+
end
|
77
|
+
|
78
|
+
def trimmed?
|
79
|
+
@trimmed
|
80
|
+
end
|
81
|
+
|
82
|
+
def inspect(level=0)
|
83
|
+
if root?
|
84
|
+
print "*"
|
85
|
+
else
|
86
|
+
print "|" unless parent.parent.children.last == parent rescue false
|
87
|
+
print(' ' * level * 4)
|
88
|
+
print(parent.children.last == self ? "+" : "|")
|
89
|
+
print "---"
|
90
|
+
print(leaf? ? ">" : "+")
|
91
|
+
end
|
92
|
+
|
93
|
+
puts " #{name} #{content.map rescue "fuck"}"
|
94
|
+
|
95
|
+
children.each { |child| child.inspect(level + 1) if child } # Child might be 'nil'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class Content
|
100
|
+
attr_accessor :items
|
101
|
+
attr_accessor :map
|
102
|
+
|
103
|
+
def initialize
|
104
|
+
@items = []
|
105
|
+
@map = {}
|
106
|
+
end
|
107
|
+
|
108
|
+
def []=(k,v)
|
109
|
+
@items << v if k == :map
|
110
|
+
@map[k] = v unless k == :map
|
111
|
+
end
|
112
|
+
|
113
|
+
def [](k)
|
114
|
+
@items[k] if Numeric === k
|
115
|
+
@map[k] unless Numeric === k
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/sansom.rb
CHANGED
@@ -1,73 +1,55 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "rack"
|
4
|
-
|
4
|
+
require_relative "./sansom/pine"
|
5
5
|
|
6
6
|
module Sansomable
|
7
|
-
class TreeContent
|
8
|
-
attr_accessor :items
|
9
|
-
def initialize
|
10
|
-
@items = []
|
11
|
-
@map = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
def []=(k,v)
|
15
|
-
@items << v if k == :map
|
16
|
-
@map[k] = v unless k == :map
|
17
|
-
end
|
18
|
-
|
19
|
-
def [](k)
|
20
|
-
@items[k] if Numeric === k
|
21
|
-
@map[k] unless Numeric === k
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
7
|
InvalidRouteError = Class.new StandardError
|
26
|
-
NoRoutesError = Class.new StandardError
|
27
|
-
InclusionError = Class.new StandardError
|
28
8
|
|
29
|
-
HTTP_VERBS = [
|
9
|
+
HTTP_VERBS = [:get,:head, :post, :put, :delete, :patch, :options].freeze
|
30
10
|
HANDLERS = ["puma", "unicorn", "thin", "webrick"].freeze
|
31
11
|
NOT_FOUND = [404, {"Content-Type" => "text/plain"}, ["Not found."]].freeze
|
32
12
|
|
33
13
|
def tree
|
34
14
|
@tree ||= nil
|
35
15
|
if @tree.nil?
|
36
|
-
@tree =
|
16
|
+
@tree = Pine::Node.new("ROOT", nil)
|
37
17
|
template if respond_to? :template
|
38
18
|
end
|
39
19
|
@tree
|
40
20
|
end
|
21
|
+
|
22
|
+
def before_block
|
23
|
+
@before_block ||= nil
|
24
|
+
end
|
41
25
|
|
42
|
-
def match
|
26
|
+
def match verb, path
|
43
27
|
components = s_parse_path(path)
|
44
28
|
matched_components = []
|
29
|
+
matched_parameters = {}
|
45
30
|
|
46
|
-
walk = components.inject(tree) do |node, component|
|
47
|
-
|
48
|
-
|
49
|
-
if child.nil?
|
31
|
+
walk = components.inject(tree) do |node, component|
|
32
|
+
if node.leaf?
|
50
33
|
node
|
51
34
|
else
|
52
35
|
matched_components << component unless component == "/"
|
53
|
-
|
36
|
+
node[component]
|
54
37
|
end
|
55
38
|
end
|
56
|
-
|
57
|
-
tc = walk.content
|
58
|
-
|
59
|
-
return nil if tc == "ROOT"
|
60
39
|
|
40
|
+
return nil if walk.root?
|
41
|
+
|
42
|
+
c = walk.content
|
61
43
|
matched_path = "/" + matched_components.join("/")
|
62
44
|
|
63
|
-
match =
|
64
|
-
match ||=
|
65
|
-
match ||=
|
45
|
+
match = c[verb.downcase.to_sym] # Check for route
|
46
|
+
match ||= c.items.select(&method(:sansom?)).reject { |item| item.match(verb, path.sub(matched_path, "")).nil? }.first rescue nil # Check subsansoms
|
47
|
+
match ||= c.items.reject(&method(:sansom?)).first rescue nil # Check for mounted rack apps
|
66
48
|
[match, matched_path]
|
67
49
|
end
|
68
50
|
|
69
51
|
def call env
|
70
|
-
return NOT_FOUND if tree.
|
52
|
+
return NOT_FOUND if tree.leaf?
|
71
53
|
|
72
54
|
r = Rack::Request.new env
|
73
55
|
|
@@ -76,12 +58,20 @@ module Sansomable
|
|
76
58
|
|
77
59
|
if item.nil?
|
78
60
|
NOT_FOUND
|
79
|
-
elsif Proc === item
|
80
|
-
item.call r
|
81
|
-
elsif sansom? item
|
82
|
-
item.call(env.dup.merge({ "PATH_INFO" => s_truncate_path(r.path_info, m.last) }))
|
83
61
|
else
|
84
|
-
|
62
|
+
if before_block
|
63
|
+
res = before_block.call r
|
64
|
+
return res if res[0].is_a?(Numeric) && res[1].is_a?(Hash) && res[2].respond_to?(:each) rescue false
|
65
|
+
end
|
66
|
+
|
67
|
+
if item.is_a? Proc
|
68
|
+
item.call r
|
69
|
+
elsif sansom? item
|
70
|
+
r.path_info.sub! m[1], ""
|
71
|
+
item.call(r.env)
|
72
|
+
else
|
73
|
+
raise InvalidRouteError, "Invalid route handler, it must be a block (proc/lambda) or a subclass of Sansom."
|
74
|
+
end
|
85
75
|
end
|
86
76
|
end
|
87
77
|
|
@@ -90,49 +80,31 @@ module Sansomable
|
|
90
80
|
Rack::Handler.pick(HANDLERS).run self, :Port => port
|
91
81
|
end
|
92
82
|
|
83
|
+
def before(&block)
|
84
|
+
@before_block = block
|
85
|
+
end
|
86
|
+
|
93
87
|
def method_missing(meth, *args, &block)
|
94
|
-
|
95
|
-
super unless
|
96
|
-
|
97
|
-
path = _args[0].dup
|
98
|
-
item = _args[1].dup
|
99
|
-
|
88
|
+
path, item = *args.dup.push(block)
|
89
|
+
return super unless path && item
|
100
90
|
return super if item == self
|
91
|
+
return super unless HTTP_VERBS.include?(meth) || meth == :map
|
101
92
|
|
102
|
-
|
103
|
-
|
104
|
-
verb = :map if meth == :map
|
105
|
-
|
106
|
-
components = s_parse_path path
|
107
|
-
components.each_with_index.inject(tree) do |node,(component, idx)|
|
108
|
-
child = node[component]
|
109
|
-
|
110
|
-
if child.nil?
|
111
|
-
newvalue = Tree::TreeNode.new(component, TreeContent.new)
|
112
|
-
node << newvalue
|
113
|
-
child = newvalue
|
114
|
-
end
|
115
|
-
|
116
|
-
child.content[verb] = item if idx == components.count-1
|
117
|
-
child
|
118
|
-
end
|
93
|
+
n = s_parse_path(path).inject(tree) { |node, comp| node.create_if_necessary comp }
|
94
|
+
n.content[meth] = item
|
119
95
|
end
|
120
96
|
|
121
97
|
private
|
122
98
|
|
123
99
|
def sansom? obj
|
124
|
-
return true if Sansom
|
100
|
+
return true if obj.is_a? Sansom
|
125
101
|
return true if obj.class.included_modules.include? Sansomable
|
126
102
|
false
|
127
103
|
end
|
128
|
-
|
104
|
+
|
129
105
|
def s_parse_path path
|
130
106
|
path.split("/").reject(&:empty?).unshift("/")
|
131
107
|
end
|
132
|
-
|
133
|
-
def s_truncate_path truncated, truncator
|
134
|
-
"/" + s_parse_path(truncated)[s_parse_path(truncator).count..-1].join("/")
|
135
|
-
end
|
136
108
|
end
|
137
109
|
|
138
110
|
Sansom = Class.new Object
|
data/sansom.gemspec
CHANGED
@@ -1,23 +1,21 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'sansom/version'
|
5
4
|
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "sansom"
|
7
|
+
s.version = "0.0.3"
|
8
|
+
s.authors = ["Nathaniel Symer"]
|
9
|
+
s.email = ["nate@natesymer.com"]
|
10
|
+
s.summary = "Flexible, versatile, light web framework named after Sansom street in Philly."
|
11
|
+
s.description = s.summary + "It's under 140 lines of code & and it's lightning fast. It uses tree-based route resolution."
|
12
|
+
s.homepage = "http://github.com/fhsjaagshs/sansom"
|
13
|
+
s.license = "MIT"
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
s.files = `git ls-files -z`.split("\x0")
|
16
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
|
+
s.require_paths = ["lib"]
|
20
19
|
|
21
|
-
|
22
|
-
spec.add_dependency "rubytree", "~> 0.9"
|
20
|
+
s.add_development_dependency "bundler", "~> 1.6"
|
23
21
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sansom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathaniel Symer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,22 +24,9 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.6'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rubytree
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0.9'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0.9'
|
41
27
|
description: Flexible, versatile, light web framework named after Sansom street in
|
42
|
-
Philly.
|
28
|
+
Philly.It's under 140 lines of code & and it's lightning fast. It uses tree-based
|
29
|
+
route resolution.
|
43
30
|
email:
|
44
31
|
- nate@natesymer.com
|
45
32
|
executables: []
|
@@ -50,10 +37,12 @@ files:
|
|
50
37
|
- Gemfile
|
51
38
|
- LICENSE.txt
|
52
39
|
- README.md
|
40
|
+
- changelog.md
|
41
|
+
- examples/before.rb
|
53
42
|
- examples/generic.rb
|
54
43
|
- examples/mixin.rb
|
55
44
|
- lib/sansom.rb
|
56
|
-
- lib/sansom/
|
45
|
+
- lib/sansom/pine.rb
|
57
46
|
- sansom.gemspec
|
58
47
|
homepage: http://github.com/fhsjaagshs/sansom
|
59
48
|
licenses:
|
data/lib/sansom/version.rb
DELETED