sansom 0.3.1 → 0.3.2

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 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