sansom 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b5864e32e2af6d42813deac99f743aa5f709377
4
- data.tar.gz: 8f7778c22852629a41aa2056c957d68fd295e8b5
3
+ metadata.gz: f29764ffc96d04c4d04a32f6205e312501003245
4
+ data.tar.gz: bcc0fee0d61526e6d1f24eacf92af8aa16c182b6
5
5
  SHA512:
6
- metadata.gz: cb966e9564c909969af9b96aa1e62e7b0eedaf345b573ee25090bf229e654bc0a978f29c0f3b736948261d0f8abf9090d84f11da3958ce83e996318b0ab10e02
7
- data.tar.gz: d5fee84cb9b078c953f72a15ad227adb9d05aad20c801aab84640b8921f2cc06f7cd8b40f68ee21eda9cead4481faf901106c62c51fef82f5bd390f085576795
6
+ metadata.gz: a6e16f0fcc5e37418367b4e67cfd135d1d62a5aabda0ec7bd2866ad9e712dafe06c826eb8e8b921f3d648c2823d9055d5f3b1ce7a5e9b57031dd67538269351e
7
+ data.tar.gz: a011da7c29be9334651a240ec0a381825b3766ba4a3cab35659c1d83b1129f36747267f1af14da9e96701c69c7d5ded2743b1cb3f9151086c3d2b890def70035
@@ -0,0 +1,79 @@
1
+ #include <iostream>
2
+ #include "pattern.h"
3
+ #include "ruby.h" // ruby header
4
+
5
+ using namespace std;
6
+
7
+ extern "C" void Init_matcher();
8
+ static lpm::pattern * getPattern(VALUE self);
9
+ static void matcher_gc_free(lpm::pattern *p);
10
+ static VALUE matcher_allocate(VALUE klass);
11
+ static VALUE matcher_initialize(VALUE self, VALUE rb_pattern);
12
+ static VALUE matcher_matches(VALUE self, VALUE rb_str);
13
+ static VALUE matcher_is_dynamic(VALUE self);
14
+ static VALUE matcher_splats(VALUE self, VALUE rb_str);
15
+ static VALUE matcher_mappings(VALUE self, VALUE rb_str);
16
+
17
+ VALUE rb_cPine = Qnil;
18
+ VALUE p_cMatcher = Qnil;
19
+
20
+ void Init_matcher() {
21
+ rb_cPine = rb_define_class("Pine", rb_cObject);
22
+ p_cMatcher = rb_define_class_under(rb_cPine, "Matcher", rb_cObject);
23
+ rb_define_alloc_func(p_cMatcher, matcher_allocate);
24
+ rb_define_method(p_cMatcher, "initialize", RUBY_METHOD_FUNC(matcher_initialize), 1);
25
+ rb_define_method(p_cMatcher, "matches?", RUBY_METHOD_FUNC(matcher_matches), 1);
26
+ rb_define_method(p_cMatcher, "dynamic?", RUBY_METHOD_FUNC(matcher_is_dynamic), 0);
27
+ rb_define_method(p_cMatcher, "splats", RUBY_METHOD_FUNC(matcher_splats), 1);
28
+ rb_define_method(p_cMatcher, "mappings", RUBY_METHOD_FUNC(matcher_mappings), 1);
29
+ }
30
+
31
+ static lpm::pattern * getPattern(VALUE self) {
32
+ lpm::pattern *p;
33
+ Data_Get_Struct(self, lpm::pattern, p);
34
+ return p;
35
+ }
36
+
37
+ static void matcher_gc_free(lpm::pattern *p) {
38
+ if (p) delete p;
39
+ p = NULL;
40
+ ruby_xfree(p);
41
+ }
42
+
43
+ static VALUE matcher_allocate(VALUE klass) {
44
+ return Data_Wrap_Struct(klass, NULL, matcher_gc_free, ruby_xmalloc(sizeof(lpm::pattern)));
45
+ }
46
+
47
+ static VALUE matcher_initialize(VALUE self, VALUE rb_pattern) {
48
+ lpm::pattern *p = getPattern(self);
49
+ new (p) lpm::pattern(StringValueCStr(rb_pattern));
50
+ return Qnil;
51
+ }
52
+
53
+ static VALUE matcher_matches(VALUE self, VALUE rb_str) {
54
+ return *(getPattern(self)) == string(StringValueCStr(rb_str)) ? Qtrue : Qfalse;
55
+ }
56
+
57
+ static VALUE matcher_is_dynamic(VALUE self) {
58
+ return getPattern(self)->is_dynamic() ? Qtrue : Qfalse;
59
+ }
60
+
61
+ static VALUE matcher_splats(VALUE self, VALUE rb_str) {
62
+ lpm::pattern *p = getPattern(self);
63
+ list<string> splats = p->extract_splats(StringValueCStr(rb_str));
64
+ VALUE ary = rb_ary_new2(splats.size());
65
+ for (list<string>::iterator i = splats.begin(); i != splats.end(); i++) {
66
+ rb_ary_push(ary, rb_str_new2((*i).c_str()));;
67
+ }
68
+ return ary;
69
+ }
70
+
71
+ static VALUE matcher_mappings(VALUE self, VALUE rb_str) {
72
+ lpm::pattern *p = getPattern(self);
73
+ map<string, string> mappings = p->extract_mappings(StringValueCStr(rb_str));
74
+ VALUE hsh = rb_hash_new();
75
+ for (map<string, string>::iterator i = mappings.begin(); i != mappings.end(); i++) {
76
+ rb_hash_aset(hsh, rb_str_new2(i->first.c_str()),rb_str_new2(i->second.c_str()));
77
+ }
78
+ return hsh;
79
+ }
@@ -0,0 +1,134 @@
1
+ #include "pattern.h"
2
+
3
+ namespace lpm {
4
+ bool pattern::operator==(const string &rhs) const { return matches(rhs); }
5
+ bool pattern::operator==(const pattern &rhs) const { return rhs._pattern == _pattern; }
6
+ bool pattern::operator!=(const string &rhs) const { return !(*this == rhs); }
7
+
8
+ bool pattern::is_dynamic() const { return (_index.size() > 0); }
9
+ string pattern::pattern_str() const { return _pattern; }
10
+
11
+ bool pattern::matches(string cppstr) const {
12
+ if (_pattern[0] == ':') return true;
13
+ if (_pattern == cppstr) return true;
14
+
15
+ char *pattern = (char *)_pattern.c_str();
16
+ char *str = (char *)cppstr.c_str();
17
+ int index_delta = 0;
18
+
19
+ for (auto i = _index.begin(); i != _index.end(); i++) {
20
+ unsigned idx = i->first;
21
+ string token = i->second;
22
+
23
+ char *vptr = str+idx+index_delta;
24
+ char *succ = pattern+idx+token.length();
25
+ unsigned succlen = (i == _index.end()) ? 0 : next(i)->first-(idx+token.length());
26
+ unsigned vlen = _advance_to_str(vptr, succ, succlen);
27
+ if (strncmp(succ, vptr, succlen) != 0) return false;
28
+
29
+ index_delta += vlen;
30
+ index_delta -= token.length();
31
+ }
32
+
33
+ return true;
34
+ }
35
+
36
+ map<string, string> pattern::extract_mappings(string cppstr) const {
37
+ map<string,string> m;
38
+ char *pattern = (char *)_pattern.c_str();
39
+ char *str = (char *)cppstr.c_str();
40
+ int index_delta = 0;
41
+
42
+ if (_pattern[0] == ':') {
43
+ m[_pattern.substr(1,_pattern.length()-1)] = cppstr;
44
+ return m;
45
+ }
46
+
47
+ for (auto i = _index.begin(); i != _index.end(); i++) {
48
+ unsigned idx = i->first;
49
+ string token = i->second;
50
+
51
+ char *vptr = str+idx+index_delta;
52
+ char *succ = pattern+idx+token.length();
53
+ unsigned succlen = (i == _index.end()) ? 0 : next(i)->first-(idx+token.length());
54
+ string value(vptr, _advance_to_str(vptr, succ, succlen));
55
+
56
+ index_delta += value.length();
57
+ index_delta -= token.length();
58
+
59
+ if (token[0] == '<' && token[token.length()-1] == '>') {
60
+ m[token.substr(1, token.length()-2)] = value;
61
+ }
62
+ }
63
+
64
+ return m;
65
+ }
66
+
67
+ list<string> pattern::extract_splats(string cppstr) const {
68
+ list<string> splats;
69
+ char *pattern = (char *)_pattern.c_str();
70
+ char *str = (char *)cppstr.c_str();
71
+ int index_delta = 0;
72
+
73
+ for (auto i = _index.begin(); i != _index.end(); i++) {
74
+ unsigned idx = i->first;
75
+ string token = i->second;
76
+
77
+ char *vptr = str+idx+index_delta;
78
+ char *succ = pattern+idx+token.length();
79
+ unsigned succlen = (i == _index.end()) ? 0 : next(i)->first-(idx+token.length());
80
+ string value(vptr, _advance_to_str(vptr, succ, succlen));
81
+
82
+ index_delta += value.length();
83
+ index_delta -= token.length();
84
+
85
+ if (token[0] == '*') splats.push_back(value);
86
+ }
87
+ return splats;
88
+ }
89
+
90
+ void pattern::create(string ptrn) {
91
+ _pattern = ptrn;
92
+ char *cptrn = (char *)_pattern.c_str();
93
+ _index = _gen_indeces(cptrn,cptrn);
94
+ }
95
+
96
+ unsigned pattern::_advance_to_str(char *&ptr, char *str, unsigned n) const {
97
+ char *start = ptr;
98
+ while (*ptr != '\0' && (*str == '\0' || strncmp(ptr, str, n) != 0)) ptr++;
99
+ return (unsigned)(ptr-start);
100
+ }
101
+
102
+ map <unsigned, string> pattern::_gen_indeces(char *str, char *ptr) const {
103
+ // advance to wildcard
104
+ while (*ptr != '\0' && !at_wildcard(ptr)) ptr++;
105
+
106
+ if (*ptr == '\0') return map <unsigned, string>();
107
+ unsigned idx = ptr-str;
108
+
109
+ // advance to characters after the pattern
110
+ char *start = ptr;
111
+ advance_past_wildcard(ptr);
112
+ unsigned token_len = (unsigned)(ptr-start);
113
+
114
+ map <unsigned, string> recursive = _gen_indeces(str, ptr);
115
+ recursive[idx] = string(str+idx,token_len);
116
+ return recursive;
117
+ }
118
+
119
+ //
120
+ // overrideable functions
121
+ //
122
+
123
+ bool pattern::at_wildcard(char * ptr) const {
124
+ return (*ptr == '*' || *ptr == '<');
125
+ }
126
+
127
+ void pattern::advance_past_wildcard(char *&ptr) const {
128
+ switch (*ptr) {
129
+ case '<': while (*ptr != '>') ptr++; ptr++; break;
130
+ case '*': ptr++; break;
131
+ default: break;
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,56 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <stdbool.h>
5
+ #include <iostream>
6
+ #include <list>
7
+ #include <map>
8
+
9
+ // TODO:
10
+ // 1. write an iterator (exposes a value and a token)
11
+ // 2. make more extensible
12
+ // 3. improve _advance_to_str function to
13
+
14
+ namespace lpm {
15
+ using namespace std;
16
+
17
+ class pattern {
18
+ public:
19
+ pattern(const char *ptrn) { create(ptrn); }
20
+ pattern(string ptrn) { create(ptrn); }
21
+
22
+ bool operator==(const string &rhs) const;
23
+ bool operator==(const pattern &rhs) const;
24
+ bool operator!=(const string &rhs) const;
25
+
26
+ // returns true if there are any wilcards/splats/etc in this
27
+ bool is_dynamic() const;
28
+
29
+ // returns the pattern used
30
+ string pattern_str() const;
31
+
32
+ // check if a string matches the this pattern
33
+ bool matches(string comp) const;
34
+
35
+ // extracts all mappings from cppstr
36
+ map<string, string> extract_mappings(string cppstr) const;
37
+
38
+ // extracts all splats from cppstr
39
+ list<string> extract_splats(string cppstr) const;
40
+ protected:
41
+ string _pattern;
42
+ map<unsigned, string> _index;
43
+
44
+ void create(string ptrn);
45
+
46
+ // return true if ptr is at a wildcard sequence
47
+ virtual bool at_wildcard(char *ptr) const;
48
+
49
+ // advance ptr to the character beyond a wildcard sequence.
50
+ virtual void advance_past_wildcard(char *&ptr) const;
51
+ private:
52
+ // advance ptr to the next occurance of str
53
+ unsigned _advance_to_str(char *&ptr, char *str, unsigned len) const;
54
+ map <unsigned, string> _gen_indeces(char *str, char *ptr) const;
55
+ };
56
+ }
@@ -24,7 +24,7 @@ module Sansomable
24
24
  def _call_handler handler, *args
25
25
  res = handler.call *args
26
26
  res = res.finish if res.is_a? Rack::Response
27
- raise ResponseError, "Response must either be a rack response, string, or object" unless Rack::Lint.fastlint res # custom method
27
+ raise ResponseError, "Response must either be a rack response, string, or object" unless Rack::Lint.fastlint res
28
28
  res = [200, {}, [res.to_str]] if res.respond_to? :to_str
29
29
  res
30
30
  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.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathaniel Symer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-04 00:00:00.000000000 Z
11
+ date: 2015-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -48,18 +48,15 @@ extensions:
48
48
  - ext/sansom/pine/extconf.rb
49
49
  extra_rdoc_files: []
50
50
  files:
51
- - ".gitignore"
52
- - Gemfile
53
- - LICENSE.txt
54
- - README.md
55
- - changelog.md
56
51
  - ext/sansom/pine/extconf.rb
52
+ - ext/sansom/pine/matcher.cpp
53
+ - ext/sansom/pine/pattern.cpp
54
+ - ext/sansom/pine/pattern.h
57
55
  - lib/rack/fastlint.rb
58
56
  - lib/sansom.rb
59
57
  - lib/sansom/pine.rb
60
58
  - lib/sansom/pine/node.rb
61
59
  - lib/sansom/sansomable.rb
62
- - sansom.gemspec
63
60
  homepage: http://github.com/fhsjaagshs/sansom
64
61
  licenses:
65
62
  - MIT
data/.gitignore DELETED
@@ -1,23 +0,0 @@
1
- ext/sansom/pine/Makefile
2
- *.gem
3
- *.rbc
4
- .bundle
5
- .config
6
- .yardoc
7
- Gemfile.lock
8
- InstalledFiles
9
- _yardoc
10
- coverage
11
- doc/
12
- lib/bundler/man
13
- pkg
14
- rdoc
15
- spec/reports
16
- test/tmp
17
- test/version_tmp
18
- tmp
19
- *.bundle
20
- *.so
21
- *.o
22
- *.a
23
- mkmf.log
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in ..gemspec
4
- gemspec
@@ -1,22 +0,0 @@
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.
data/README.md DELETED
@@ -1,232 +0,0 @@
1
- Sansom
2
- ===
3
-
4
- No-nonsense web 'picowork' named after Sansom street in Philly, near where it was made.
5
-
6
- Philosophy
7
- -
8
-
9
- ***A framework should not limit you to one way of thinking.***
10
-
11
- - You can write a `Sansomable` for each logical unit of your API, but you also don't have to.
12
-
13
- - You can also mount existing Rails/Sinatra/Rack apps in your `Sansomable`. But you also don't have to.
14
-
15
- - You can write one `Sansomable` for your entire API.
16
-
17
- Fuck it.
18
-
19
- ***A tool should do one thing, and do it well. (Unix philosophy)***
20
-
21
- A web framework is, fundamentally, a tool to connect code to a URL's path. Therefore, a web framework doesn't provide an ORM, template rendering, shortcuts, nor security patches.
22
-
23
- ***A web framework shall remain a framework***
24
-
25
- No single tool should get so powerful that it can overcome its master. Rails and Sinatra have been doing this: modifying the language beyond recognition. Rails has activerecord and Sinatra's blocks aren't really blocks.
26
-
27
- Installation
28
- -
29
-
30
- `gem install sansom`
31
-
32
- Or, you can clone this repo and use `gem build sansom.gemspec` to build the gem.
33
-
34
- Writing a Sansom app
35
- -
36
- Writing a one-file application is trivial with Sansom:
37
-
38
- # config.ru
39
-
40
- require "sansom"
41
-
42
- class MyAPI
43
- include Sansomable
44
- def routes
45
- # define routes here
46
- end
47
- end
48
-
49
- run MyAPI.new
50
-
51
- Defining Routes
52
- -
53
- Routes are defined through (dynamically resolved) instance methods that correspond to HTTP verbs. They take a path and a block. The block must be able to accept (at least) **one** argument.
54
-
55
- You can either write
56
-
57
- require "sansom"
58
-
59
- class MyAPI
60
- include Sansomable
61
- def routes
62
- get "/" do |r|
63
- # r is a Rack::Request object
64
- [200, {}, ["hello world!"]]
65
- end
66
-
67
- post "/form" do |r|
68
- # return a Rack response
69
- end
70
- end
71
- end
72
-
73
-
74
- Routes can also be defined like so:
75
-
76
- s = MyAPI.new
77
- s.get "/" do |r| # r is a Rack::Request
78
- [200, {}, ["Return a Rack response."]]
79
- end
80
-
81
- But let's say you have an existing Sinatra/Rails/Sansom (Rack) app. It's simple: mount them. For example, mounting existing applications can be used to easily version an app:
82
-
83
- # config.ru
84
-
85
- require "sansom"
86
-
87
- class Versioning
88
- include Sansomable
89
- end
90
-
91
- s = Versioning.new
92
- s.mount "/v1", MyAPI.new
93
- s.mount "/v2", MyNewAPI.new
94
-
95
- run s
96
-
97
- Sansom routes vs Sinatra routes
98
- -
99
-
100
- **Sansom routes remain true blocks**: When a route is mapped, the same block you use is called when a route is matched. It's the same object every time.
101
-
102
- **Sinatra routes become methods behind the scenes**: When a route is matched, Sinatra looks up the method and calls it.
103
-
104
- It's a common idiom in Sinatra to use `return` to terminate execution of a route prematurely (since Sinatra routes aren't blocks). **You must use `next` instead** (you can relplace all instances of `return` with `next`).
105
-
106
- Before filters
107
- -
108
-
109
- You can write before filters to try to preëmpt request processing. If the block returns anything (other than nil) **the request is preëmpted**. In that case, the response from the before block is the response for the request.
110
-
111
- # app.rb
112
-
113
- require "sansom"
114
-
115
- s = Sansom.new
116
- s.before do |r|
117
- [200, {}, ["Preëmpted."]] if some_condition
118
- end
119
-
120
- You could use this for request statistics, caching, auth, etc.
121
-
122
- After filters
123
- -
124
-
125
- Called after a route is called. If they return a non-nil response, that response is used instead of the response from a route. After filters are not called if a before filter preëmpted route execution.
126
-
127
- # app.rb
128
-
129
- require "sansom"
130
-
131
- s = Sansom.new
132
- s.after do |req,res| # req is a Rack::Request and res is the response generated by a route.
133
- next [200, {}, ["Postëmpted."]] if some_condition
134
- end
135
-
136
- Errors
137
- -
138
-
139
- Error blocks allow for the app to return something parseable when an error is raised.
140
-
141
- require "sansom"
142
- require "json"
143
-
144
- s = Sansom.new
145
- s.error do |r, err| # err is the error, r is a Rack::Request
146
- [500, {"yo" => "headers"}, [{ :message => err.message }.to_json]]
147
- end
148
-
149
- There is also a unique error 404 handler:
150
-
151
- require "sansom"
152
- require "json"
153
-
154
- s = Sansom.new
155
- s.not_found do |r| # r is a Rack::Request
156
- [404, {"yo" => "shit"}, [{ :message => "not found" }.to_json]]
157
- end
158
-
159
- Matching
160
- -
161
-
162
- `Sansom` uses trees to match routes. It follows a certain set of rules:
163
-
164
- 1. The route matching the path and verb. Routes have a sub-order:
165
- 1. "Static" paths
166
- 2. Wildcards (see below)
167
- 1. Full mappings (kinda a non-compete)
168
- 2. Partial mappings
169
- 3. Splats
170
- 3. The first Subsansom that matches the route & verb
171
- 4. The first mounted non-`Sansom` rack app matching the route
172
-
173
-
174
- Wildcards
175
- -
176
-
177
- Sansom supports multiple wildcards:
178
-
179
- `/path/to/:resource/:action` - Full mapping
180
- `/path/to/resource.<format>` - Partial mapping
181
- `/path/to/*.json` - Splat
182
- `/path/to/*.<format>.<compression>` - You can mix them.
183
-
184
- Mappings map part of the route (for example `format` above) to the corresponding part of the matched path (for `/resource.<format>` and `/resource.json` yields a mapping of `format`:`json`).
185
-
186
- Mappings (full and partial) are available in `Rack::Request#params` **by name**, and splats are available under the key `splats` in `Rack::Request#params`.
187
-
188
- *See the Matching section of this readme for wildcard precedence.*
189
-
190
-
191
- Notes
192
- -
193
-
194
- - `Sansom` does not pollute _any_ `Object` methods, including `initialize`
195
- - No regexes are used in the entire project.
196
- - Has one dependency: `rack`
197
- - `Sansom` is under **400** lines of code at the time of writing. This includes
198
- * Rack conformity & the DSL (`sansom.rb`) (~90 lines)
199
- * Custom tree-based routing (`sanom/pine.rb`) (~150 lines)
200
- * libpatternmatch (~150 lines of C++)
201
-
202
- Speed
203
- -
204
-
205
- Well, that's great and all, but how fast is "hello world" example in comparision to Rack or Sinatra?
206
-
207
- Rack: **11ms**<br />
208
- Sansom: **14ms**\*†<br />
209
- Sinatra: **28ms**<br />
210
- Rails: **34ms****
211
-
212
- (results are measured locally using Puma and are rounded down)
213
-
214
- Hey [Konstantine](https://github.com/rkh), *put that in your pipe and smoke it*.
215
-
216
- \* Uncached. If a tree lookup is cached, it takes the same time as Rack.
217
-
218
- † Sansom's speed (compared to Sinatra) may be because it doesn't load any middleware by default.
219
-
220
- \** Rails loads a rich welcome page which may contribute to its slowness
221
-
222
- Todo
223
- -
224
-
225
- * Multiple return types for routes
226
-
227
- If you have any ideas, let me know!
228
-
229
- Contributing
230
- -
231
-
232
- You know the drill. But ** make sure you don't add tons and tons of code. Part of `Sansom`'s beauty is its brevity.**
@@ -1,76 +0,0 @@
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
31
-
32
- 0.0.4
33
-
34
- - Fixed bug with with requiring pine
35
-
36
- 0.0.5
37
-
38
- - Parameterized URLs!!! (Stuff like `/user/:id/profile`)
39
- * Parameterized URLs work with mounted Rack/Sansom apps
40
- - Improved matching efficiency
41
-
42
- 0.0.6
43
-
44
- - `before` block response checking
45
-
46
- 0.0.7
47
-
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.
50
-
51
- 0.1.0
52
-
53
- - PUBLIC RELEASE!
54
- - `after` block
55
- - Improved routing behavior & speed
56
-
57
- 0.1.1
58
-
59
- - Fix bad bug in method_missing
60
- - Added better error handling (per-error handling and a generic block that gets called if no specific handler is present)
61
-
62
- 0.1.2
63
-
64
- - Fixed issue with `include` in the `Sansom` class
65
-
66
- 0.2.0
67
-
68
- - Rewrite internals to:
69
- 1. Avoid collisions with the including class
70
- 2. Improve performance
71
- 3. Look better
72
- 4. **Avoid bugs**
73
-
74
- - Route match caching by path and HTTP method
75
- &nbsp;&nbsp;->Should improve performance for static paths dramatically
76
-
@@ -1,24 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "sansom"
7
- s.version = "0.3.1"
8
- s.authors = ["Nathaniel Symer"]
9
- s.email = ["nate@natesymer.com"]
10
- s.summary = "Scientific, philosophical, abstract web 'picowork' named after Sansom street in Philly, near where it was made."
11
- s.description = s.summary + " " + "It's under 200 lines of code & it's lightning fast. It uses tree-based route resolution."
12
- s.homepage = "http://github.com/fhsjaagshs/sansom"
13
- s.license = "MIT"
14
-
15
- allfiles = `git ls-files -z`.split("\x0")
16
- s.files = allfiles.grep(%r{(^[^\/]*$|^lib\/)}) # Match all lib files AND files in the root
17
- s.extensions = ["ext/sansom/pine/extconf.rb"]
18
- s.executables = allfiles.grep(%r{^bin/}) { |f| File.basename(f) }
19
- s.test_files = allfiles.grep(%r{^(test|spec|features)/})
20
- s.require_paths = ["lib"]
21
-
22
- s.add_development_dependency "bundler", "~> 1.6"
23
- s.add_dependency "rack", "~> 1"
24
- end