sansom 0.0.7 → 0.1.0
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/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
|