sansom 0.0.2 → 0.0.3
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.
- 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