sansom 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7c54015af146ba89239c6199fa38f6d32674f274
4
+ data.tar.gz: 01b09122f5014d586311449942d84962a51b1a89
5
+ SHA512:
6
+ metadata.gz: 806566785d4903fb29413b9c4606f259b154b2f6dc946139e20341ed69a08385c533818bbd1a5eab8553c3622387a22e51261a910b309e0e22810c0eba4f6733
7
+ data.tar.gz: 5805d9c95195d8b5b9ce80f20b0dbee5df425877f28ff63dba3f34dee3198969fd3ce4ee57282ec84e8f2c5f82aca291aa71be03fd8df5bc1aedb6542b4d3914
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ..gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Nathaniel Symer
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,173 @@
1
+ Sansom
2
+ ===
3
+
4
+ Flexible, versatile, light web framework named after Sansom street in Philly.
5
+
6
+ Installation
7
+ -
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem '.'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install .
20
+
21
+ Usage
22
+ -
23
+
24
+ It's pretty simple. Instead of `Class`s storing routes, `Object`s store routes.
25
+
26
+ There are two ways you can deploy `Sansom`:
27
+
28
+ # app.rb
29
+
30
+ #!/usr/bin/env ruby
31
+
32
+ require "sansom"
33
+
34
+ s = Sansom.new
35
+ s.get "/" do |r|
36
+ # r is a Rack::Request
37
+ [200, { "Content-Type" => "text/plain" }, ["Hello Sansom"]]
38
+ end
39
+ s.start
40
+
41
+ Or, the more production-ready version:
42
+
43
+ # config.ru
44
+
45
+ require "sansom"
46
+
47
+ s = Sansom.new
48
+
49
+ s.get "/" do |r|
50
+ # r is a Rack::Request
51
+ [200, { "Content-Type" => "text/plain" }, ["Hello Sansom"]]
52
+ end
53
+
54
+ run s
55
+
56
+ But `Sansom` can do more than just that:
57
+
58
+ It can be used in a similar fashion to Sinatra:
59
+
60
+ # myapi.rb
61
+
62
+ #!/usr/bin/env ruby
63
+
64
+ require "sansom"
65
+
66
+ class MyAPI < Sansom
67
+ # This method is used to define Sansom routes
68
+ def template
69
+ get "/" do |r|
70
+ [200, { "Content-Type" => "text/plain" }, ["Hello Sansom"]]
71
+ # r is a Rack::Request
72
+ end
73
+ end
74
+ end
75
+
76
+ And your `config.ru` file
77
+
78
+ # config.ru
79
+
80
+ require "sansom"
81
+ require "./myapi"
82
+
83
+ run MyAPI.new
84
+
85
+ Sansom can also map other instances of Sansom to a route. Check this:
86
+
87
+ # myapi.rb
88
+
89
+ #!/usr/bin/env ruby
90
+
91
+ require "sansom"
92
+
93
+ class MyAPI < Sansom
94
+ # This method is used to define Sansom routes
95
+ def template
96
+ get "/" do |r|
97
+ [200, { "Content-Type" => "text/plain" }, ["Hello Sansom"]]
98
+ # r is a Rack::Request
99
+ end
100
+ end
101
+ end
102
+
103
+ Let's say you've written a new version of your api. No problem.
104
+
105
+ # app.rb
106
+
107
+ require "sansom"
108
+
109
+ s = Sansom.new
110
+ s.map "/v1", MyAPI.new
111
+ s.map "/v2", MyNewAPI.new
112
+ s.start
113
+
114
+ Or maybe you want to mount your Rails/Sinatra/whatever app
115
+
116
+ # app.rb
117
+
118
+ require "sansom"
119
+
120
+ s = Sansom.new
121
+ s.map "/api", SinatraApp.new
122
+ s.map "/", RailsApp.new
123
+ s.start
124
+
125
+ Lastly, any object can become a "`Sansom`" through a mixin:
126
+
127
+ # mixin.ru
128
+
129
+ class Mixin < Hash
130
+ include Sansomable
131
+
132
+ def template
133
+ get "/sansomable" do |r|
134
+ [200, { "Content-Type" => "text/plain"}, ["Sansomable Hash"]]
135
+ end
136
+ end
137
+ end
138
+
139
+ run Mixin.new
140
+
141
+ If you look at how `Sansom` is defined, it makes sense:
142
+
143
+ Sansom = Class.new Object
144
+ Sansom.include Sansomable
145
+
146
+ Matching
147
+ -
148
+
149
+ `Sansom` uses trees to match routes. It follows a certain set of rules:
150
+
151
+ - A matching order is enforced:
152
+ 1. The route matching the path and verb
153
+ 2. The first Subsansom that matches the route & verb
154
+ 3. The first mounted non-`Sansom` rack app matching the route
155
+
156
+ Notes
157
+ -
158
+
159
+ - `Sansom` does not pollute _any_ `Object` methods, including `initialize`
160
+ - `Sansom` is under **140** lines of code at the time of writing. This includes
161
+ * Everything above
162
+ * Custom routing
163
+
164
+ Contributing
165
+ -
166
+
167
+ 1. Fork it
168
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
169
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
170
+ 4. Push to the branch (`git push origin my-new-feature`)
171
+ 5. Create a new Pull Request
172
+
173
+ **Please make sure you don't add tons and tons of code. Part of `Sansom`'s beauty is is brevity.**
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "json"
4
+ require "sansom"
5
+
6
+ class Sansom
7
+ def food_response r
8
+ [200, { "Content-Type" => "text/plain"}, [{ :type => self.class.to_s, :name => r.path_info.split("/").reject(&:empty?).last}.to_json]]
9
+ end
10
+ end
11
+
12
+ class Meat < Sansom
13
+ def template
14
+ get "/pork" do |r|
15
+ food_response r
16
+ end
17
+ end
18
+ end
19
+
20
+ class NonAnimal < Sansom
21
+ def template
22
+ get "/quinoa" do |r|
23
+ food_response r
24
+ end
25
+
26
+ get "/tahini" do |r|
27
+ food_response r
28
+ end
29
+
30
+ get "/squash" do |r|
31
+ food_response r
32
+ end
33
+ end
34
+ end
35
+
36
+ class AnimalProducts < Sansom
37
+ def template
38
+ get "/eggs" do |r|
39
+ food_response r
40
+ end
41
+
42
+ get "/milk" do |r|
43
+ food_response r
44
+ end
45
+ end
46
+ end
47
+
48
+ class FoodTypes < Sansom
49
+ def template
50
+ map "/carnivorous", Meat.new
51
+ map "/vegetarian", NonAnimal.new
52
+ map "/vegetarian", AnimalProducts.new
53
+ map "/vegan", NonAnimal.new
54
+ end
55
+ end
56
+
57
+ class Food < Sansom
58
+ def template
59
+ get "/sushi" do |r|
60
+ [200, { "Content-Type" => "text/plain"}, ["Quite delicious, especially cucumber"]]
61
+ end
62
+
63
+ map "/types", FoodTypes.new
64
+ end
65
+ end
66
+
67
+ s = Sansom.new
68
+
69
+ s.get "/" do |r|
70
+ [200, { "Content-Type" => "text/plain"}, ["root"]]
71
+ end
72
+
73
+ s.get "/something" do |r|
74
+ [200, { "Content-Type" => "text/plain"}, ["something"]]
75
+ end
76
+
77
+ s.map "/food", Food.new
78
+
79
+ s.start 2000
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "sansom"
4
+
5
+ class Mixin < Hash
6
+ include Sansomable
7
+
8
+ def template
9
+ get "/sansomable" do |r|
10
+ [200, { "Content-Type" => "text/plain"}, ["Sansomable Hash"]]
11
+ end
12
+ end
13
+ end
14
+
15
+ s = Sansom.new
16
+
17
+ s.get "/" do |r|
18
+ [200, { "Content-Type" => "text/plain"}, ["root"]]
19
+ end
20
+
21
+ s.map "/mixins", Mixin.new
22
+ s.start 3002
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rack"
4
+ require "tree" # rubytree
5
+
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
+ InvalidRouteError = Class.new StandardError
26
+ NoRoutesError = Class.new StandardError
27
+ InclusionError = Class.new StandardError
28
+
29
+ HTTP_VERBS = ["GET","HEAD","POST","PUT","DELETE","PATCH","OPTIONS"].freeze
30
+ HANDLERS = ["puma", "unicorn", "thin", "webrick"].freeze
31
+ NOT_FOUND = [404, {"Content-Type" => "text/plain"}, ["Not found."]].freeze
32
+
33
+ def tree
34
+ @tree ||= nil
35
+ if @tree.nil?
36
+ @tree = Tree::TreeNode.new("ROOT", "ROOT")
37
+ template if respond_to? :template
38
+ end
39
+ @tree
40
+ end
41
+
42
+ def match http_method, path
43
+ components = s_parse_path(path)
44
+ matched_components = []
45
+
46
+ walk = components.inject(tree) do |node, component|
47
+ child = node[component]
48
+
49
+ if child.nil?
50
+ node
51
+ else
52
+ matched_components << component unless component == "/"
53
+ child
54
+ end
55
+ end
56
+
57
+ tc = walk.content
58
+
59
+ return nil if tc == "ROOT"
60
+
61
+ matched_path = "/" + matched_components.join("/")
62
+
63
+ match = tc[http_method] # Check for route
64
+ match ||= tc.items.select(&method(:sansom?)).reject { |item| item.match(http_method, s_truncate_path(path, matched_path)).nil? }.first rescue nil # Check subsansoms
65
+ match ||= tc.items.reject(&method(:sansom?)).first rescue nil # Check for mounted rack apps
66
+ [match, matched_path]
67
+ end
68
+
69
+ def call env
70
+ return NOT_FOUND if tree.children.empty?
71
+
72
+ r = Rack::Request.new env
73
+
74
+ m = match r.request_method, r.path_info
75
+ item = m.first
76
+
77
+ if item.nil?
78
+ 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
+ else
84
+ raise InvalidRouteError, "Invalid route handler, it must be a block (proc/lambda) or a subclass of Sansom."
85
+ end
86
+ end
87
+
88
+ def start port=3001
89
+ raise NoRoutesError if tree.children.empty?
90
+ Rack::Handler.pick(HANDLERS).run self, :Port => port
91
+ end
92
+
93
+ def method_missing(meth, *args, &block)
94
+ _args = args.dup.push block
95
+ super unless _args.count >= 2
96
+
97
+ path = _args[0].dup
98
+ item = _args[1].dup
99
+
100
+ return super if item == self
101
+
102
+ verb = meth.to_s.strip.upcase
103
+ return super unless HTTP_VERBS.include?(verb) || meth == :map
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
119
+ end
120
+
121
+ private
122
+
123
+ def sansom? obj
124
+ return true if Sansom === obj
125
+ return true if obj.class.included_modules.include? Sansomable
126
+ false
127
+ end
128
+
129
+ def s_parse_path path
130
+ path.split("/").reject(&:empty?).unshift("/")
131
+ end
132
+
133
+ def s_truncate_path truncated, truncator
134
+ "/" + s_parse_path(truncated)[s_parse_path(truncator).count..-1].join("/")
135
+ end
136
+ end
137
+
138
+ Sansom = Class.new Object
139
+ Sansom.include Sansomable
@@ -0,0 +1,3 @@
1
+ module Sansom
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sansom/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sansom"
8
+ spec.version = Sansom::VERSION
9
+ spec.authors = ["Nathaniel Symer"]
10
+ spec.email = ["nate@natesymer.com"]
11
+ spec.summary = %q{Flexible, versatile, light web framework named after Sansom street in Philly.}
12
+ spec.description = %q{Flexible, versatile, light web framework named after Sansom street in Philly. It's under 140 lines of code & and it's lightning fast.}
13
+ spec.homepage = "http://github.com/fhsjaagshs/sansom"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_dependency "rubytree", "~> 0.9"
23
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sansom
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Nathaniel Symer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
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
+ description: Flexible, versatile, light web framework named after Sansom street in
42
+ Philly. It's under 140 lines of code & and it's lightning fast.
43
+ email:
44
+ - nate@natesymer.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - examples/generic.rb
54
+ - examples/mixin.rb
55
+ - lib/sansom.rb
56
+ - lib/sansom/version.rb
57
+ - sansom.gemspec
58
+ homepage: http://github.com/fhsjaagshs/sansom
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.2.2
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Flexible, versatile, light web framework named after Sansom street in Philly.
82
+ test_files: []