sansom 0.0.7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -3
- data/changelog.md +7 -1
- data/lib/rack/fastlint.rb +7 -8
- data/lib/sansom.rb +37 -30
- data/lib/sansom/pine.rb +33 -49
- data/sansom.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9fe8ba21c0cab848b10f8484f8f38a0454d2f549
|
4
|
+
data.tar.gz: dccfd78c121e2b6f6bc5c01f42bce52f8809ea93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 773fded808375146ea57bf266e68feb8ad2c27ee584590e568d98d9517401f24b07a52f6f8dabab5da0e34114617fcce3b610a5683a77c02c17a10f33b59d93b
|
7
|
+
data.tar.gz: f004a23139c2dd2b1664868507815e1f149064f0511d35a5804efe818f16eabbb1e199d7afd90aa24f9a4162c090891200d24ff4cb60499a1edda90dea3bdc86
|
data/README.md
CHANGED
@@ -6,14 +6,22 @@ Scientific, philosophical, abstract web 'picowork' named after Sansom street in
|
|
6
6
|
Philosophy
|
7
7
|
-
|
8
8
|
|
9
|
-
|
9
|
+
***A piece of software should not limit you to one way of thinking.***
|
10
10
|
|
11
11
|
You can write a `Sansomable` for each logical unit of your API, but you also don't have to.
|
12
12
|
|
13
|
-
You can also mount existing Rails/Sinatra apps in your `Sansomable`. But you also don't have to.
|
13
|
+
You can also mount existing Rails/Sinatra/Rack apps in your `Sansomable`. But you also don't have to.
|
14
14
|
|
15
15
|
You can write one `Sansomable` for your entire API.
|
16
16
|
|
17
|
+
Fuck it.
|
18
|
+
|
19
|
+
***A piece of software should not be a magic box.***
|
20
|
+
|
21
|
+
A web framework is, however simplistically, a tool to connect code to a URL's path.
|
22
|
+
|
23
|
+
A web framework doesn't provide an ORM, template rendering, nor change how ruby works to the point where you're not writing Ruby code but instead `Rails` or `Sinatra` code.
|
24
|
+
|
17
25
|
Installation
|
18
26
|
-
|
19
27
|
|
@@ -160,7 +168,7 @@ Notes
|
|
160
168
|
-
|
161
169
|
|
162
170
|
- `Sansom` does not pollute _any_ `Object` methods, including `initialize`
|
163
|
-
- `Sansom` is under **
|
171
|
+
- `Sansom` is under **250** lines of code at the time of writing. This includes
|
164
172
|
* Rack conformity & the DSL (`sansom.rb`)
|
165
173
|
* Custom tree-based routing (`pine.rb`)
|
166
174
|
|
data/changelog.md
CHANGED
@@ -46,4 +46,10 @@ Here's an example
|
|
46
46
|
0.0.7
|
47
47
|
|
48
48
|
- Fixed bug where a wilcard path component would be ignored if it came last in the URL
|
49
|
-
- Fixed a bug where async responses would be marked as bad by the fastlinter.
|
49
|
+
- Fixed a bug where async responses would be marked as bad by the fastlinter.
|
50
|
+
|
51
|
+
0.1.0
|
52
|
+
|
53
|
+
- PUBLIC RELEASE!
|
54
|
+
- After block added
|
55
|
+
- Improved routing behavior & speed
|
data/lib/rack/fastlint.rb
CHANGED
@@ -4,7 +4,6 @@ require "rack"
|
|
4
4
|
|
5
5
|
module Rack
|
6
6
|
class Fastlint
|
7
|
-
LintError = Class.new StandardError
|
8
7
|
def self.response res
|
9
8
|
return false unless res.kind_of?(Array) && res.count == 3
|
10
9
|
|
@@ -21,15 +20,15 @@ module Rack
|
|
21
20
|
begin
|
22
21
|
headers.each { |k,v|
|
23
22
|
next if key =~ /^rack\..+$/
|
24
|
-
throw
|
25
|
-
throw
|
26
|
-
throw
|
27
|
-
throw
|
28
|
-
throw
|
29
|
-
throw
|
23
|
+
throw StandardError unless k.kind_of? String
|
24
|
+
throw StandardError unless v.kind_of? String
|
25
|
+
throw StandardError if k.downcase == "status"
|
26
|
+
throw StandardError unless k !~ /[:\n]/
|
27
|
+
throw StandardError unless k !~ /[-_]\z/
|
28
|
+
throw StandardError unless k =~ /\A[a-zA-Z][a-zA-Z0-9_-]*\z/
|
30
29
|
}
|
31
30
|
|
32
|
-
body.each { |part| throw
|
31
|
+
body.each { |part| throw StandardError unless part.kind_of? String }
|
33
32
|
rescue StandardError
|
34
33
|
return false
|
35
34
|
end
|
data/lib/sansom.rb
CHANGED
@@ -6,10 +6,10 @@ require_relative "./rack/fastlint.rb"
|
|
6
6
|
|
7
7
|
module Sansomable
|
8
8
|
InvalidRouteError = Class.new StandardError
|
9
|
-
HTTP_VERBS = [:get,:head, :post, :put, :delete, :patch, :options].freeze
|
10
|
-
|
9
|
+
HTTP_VERBS = [:get,:head, :post, :put, :delete, :patch, :options, :link, :unlink, :trace].freeze
|
10
|
+
RACK_HANDLERS = ["puma", "unicorn", "thin", "webrick"].freeze
|
11
11
|
NOT_FOUND = [404, {}, ["Not found."]].freeze
|
12
|
-
|
12
|
+
|
13
13
|
def tree
|
14
14
|
if @tree.nil?
|
15
15
|
@tree = Pine::Node.new "ROOT"
|
@@ -19,49 +19,56 @@ module Sansomable
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def call env
|
22
|
-
return NOT_FOUND if tree.leaf?
|
22
|
+
return NOT_FOUND if tree.leaf? && tree.root?
|
23
23
|
|
24
24
|
r = Rack::Request.new env
|
25
|
+
m = tree.match r.path_info, r.request_method
|
26
|
+
|
27
|
+
return NOT_FOUND if m.nil?
|
25
28
|
|
26
|
-
if @before_block
|
27
|
-
|
28
|
-
return
|
29
|
+
if @before_block && @before_block.arity == 1
|
30
|
+
bres = @before_block.call r
|
31
|
+
return bres if Rack::Fastlint.response bres
|
29
32
|
end
|
30
33
|
|
31
|
-
m
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
s = q.map { |p| p.join '=' }.join("&")
|
39
|
-
r.env["rack.request.query_hash"] = q
|
40
|
-
r.env["rack.request.query_string"] = s
|
41
|
-
r.env["QUERY_STRING"] = s
|
42
|
-
r.instance_variable_set "@params", r.POST.merge(q)
|
43
|
-
end
|
44
|
-
|
45
|
-
if m.item.is_a? Proc
|
46
|
-
m.item.call r
|
47
|
-
elsif m.item.respond_to? :call
|
48
|
-
r.env["PATH_INFO"] = m.remaining_path
|
49
|
-
m.item.call r.env
|
50
|
-
else
|
51
|
-
raise InvalidRouteError, "Route handlers must be blocks or valid rack apps."
|
52
|
-
end
|
34
|
+
if m.url_params.count > 0
|
35
|
+
q = r.params.merge m.url_params
|
36
|
+
s = q.map { |p| p.join '=' }.join '&'
|
37
|
+
r.env["rack.request.query_hash"] = q
|
38
|
+
r.env["rack.request.query_string"] = s
|
39
|
+
r.env["QUERY_STRING"] = s
|
40
|
+
r.instance_variable_set "@params", r.POST.merge(q)
|
53
41
|
end
|
42
|
+
|
43
|
+
case m.item
|
44
|
+
when Proc then res = m.item.call r
|
45
|
+
else
|
46
|
+
raise InvalidRouteError, "Route handlers must be blocks or valid rack apps." unless m.item.respond_to? :call
|
47
|
+
r.env["PATH_INFO"] = m.remaining_path
|
48
|
+
res = m.item.call r.env
|
49
|
+
end
|
50
|
+
|
51
|
+
if @after_block && @after_block.arity == 2
|
52
|
+
ares = @after_block.call r, res
|
53
|
+
return ares if Rack::Fastlint.response ares
|
54
|
+
end
|
55
|
+
|
56
|
+
res
|
54
57
|
end
|
55
58
|
|
56
59
|
def start port=3001
|
57
60
|
raise NoRoutesError if tree.leaf?
|
58
|
-
Rack::Handler.pick(
|
61
|
+
Rack::Handler.pick(RACK_HANDLERS).run self, :Port => port
|
59
62
|
end
|
60
63
|
|
61
64
|
def before &block
|
62
65
|
@before_block = block
|
63
66
|
end
|
64
67
|
|
68
|
+
def after &block
|
69
|
+
@after_block = block
|
70
|
+
end
|
71
|
+
|
65
72
|
def method_missing meth, *args, &block
|
66
73
|
path, item = *args.dup.push(block)
|
67
74
|
return super unless path && item
|
data/lib/sansom/pine.rb
CHANGED
@@ -4,35 +4,28 @@
|
|
4
4
|
|
5
5
|
module Pine
|
6
6
|
Result = Struct.new :item, :remaining_path, :url_params
|
7
|
-
|
7
|
+
|
8
8
|
class Content
|
9
|
-
|
9
|
+
attr_reader :items, :map
|
10
10
|
|
11
11
|
def initialize
|
12
12
|
@items = []
|
13
13
|
@map = {}
|
14
14
|
end
|
15
|
-
|
16
|
-
def
|
15
|
+
|
16
|
+
def set k,v
|
17
17
|
@items << v if k == :map
|
18
18
|
@map[k] = v unless k == :map
|
19
19
|
end
|
20
|
-
|
21
|
-
def [] k
|
22
|
-
@items[k] if Numeric === k
|
23
|
-
@map[k] unless Numeric === k
|
24
|
-
end
|
25
20
|
end
|
26
21
|
|
27
22
|
class Node
|
28
|
-
attr_reader :name, :parent
|
29
|
-
|
30
|
-
|
31
|
-
def initialize name, content=Content.new
|
23
|
+
attr_reader :name, :parent, :content
|
24
|
+
|
25
|
+
def initialize name
|
32
26
|
@name = name
|
33
|
-
@content =
|
27
|
+
@content = Content.new
|
34
28
|
@children = {}
|
35
|
-
@parent = nil
|
36
29
|
end
|
37
30
|
|
38
31
|
def root?
|
@@ -48,45 +41,33 @@ module Pine
|
|
48
41
|
end
|
49
42
|
|
50
43
|
def [] k
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
return child if child.wildcard?
|
55
|
-
nil
|
56
|
-
# return @children[k] || @children.values.first
|
57
|
-
end
|
58
|
-
|
59
|
-
def create_and_save comp
|
60
|
-
child = self.class.new comp
|
61
|
-
child.instance_variable_set "@parent", self
|
62
|
-
@children[comp] = child
|
63
|
-
child
|
44
|
+
return @children[k] if @children.member? k
|
45
|
+
c = @children.values.first
|
46
|
+
return c if (c.wildcard? rescue false)
|
64
47
|
end
|
65
48
|
|
66
49
|
def << comp
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
child
|
72
|
-
|
73
|
-
child
|
50
|
+
child = self[comp]
|
51
|
+
|
52
|
+
if child.nil?
|
53
|
+
child = self.class.new comp
|
54
|
+
child.instance_variable_set "@parent", self
|
55
|
+
@children.reject!(&:leaf?) if child.wildcard?
|
56
|
+
@children[comp] = child
|
74
57
|
end
|
75
|
-
end
|
76
58
|
|
77
|
-
|
59
|
+
child
|
60
|
+
end
|
61
|
+
|
62
|
+
def parse_path path
|
78
63
|
c = path.split "/"
|
79
|
-
|
80
|
-
c[0] = '/'
|
81
|
-
else
|
82
|
-
c.delete_at(0) if c[0].empty?
|
83
|
-
end
|
64
|
+
c[0] = '/'
|
84
65
|
c.delete_at(-1) if c[-1].empty?
|
85
66
|
c
|
86
67
|
end
|
87
68
|
|
88
69
|
def map_path path, item, key
|
89
|
-
parse_path(path).inject(self) { |node, comp| node << comp }.content
|
70
|
+
parse_path(path).inject(self) { |node, comp| node << comp }.content.set key, item
|
90
71
|
path
|
91
72
|
end
|
92
73
|
|
@@ -95,15 +76,18 @@ module Pine
|
|
95
76
|
matched_params = {}
|
96
77
|
|
97
78
|
walk = parse_path(path).inject self do |node, comp|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
79
|
+
break node if node.leaf?
|
80
|
+
next node[comp] if node.root?
|
81
|
+
|
82
|
+
c = node[comp]
|
83
|
+
break node if c.nil?
|
84
|
+
matched_comps << comp
|
85
|
+
matched_params[c.name[1..-1]] = comp if c.wildcard?
|
86
|
+
c
|
103
87
|
end
|
104
88
|
|
105
89
|
return nil if walk.nil?
|
106
|
-
return nil if walk.root?
|
90
|
+
return nil if walk.root?
|
107
91
|
|
108
92
|
c = walk.content
|
109
93
|
subpath = path.sub "/#{matched_comps.join("/")}", ""
|
data/sansom.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "sansom"
|
7
|
-
s.version = "0.0
|
7
|
+
s.version = "0.1.0"
|
8
8
|
s.authors = ["Nathaniel Symer"]
|
9
9
|
s.email = ["nate@natesymer.com"]
|
10
10
|
s.summary = "Scientific, philosophical, abstract web 'picowork' named after Sansom street in Philly, near where it was made."
|
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.1.0
|
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-08-
|
11
|
+
date: 2014-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|