immanence 0.0.2 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +7 -5
- data/Rakefile +9 -0
- data/lib/immanence.rb +65 -42
- data/lib/immanence/version.rb +1 -1
- data/spec/immanence_spec.rb +49 -0
- data/spec/spec_helper.rb +3 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MTZkMWFhOGNhODAxOGMyNzYyNTcwNDBhMmEzZWVjNTc3ZTk4ODJlYQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YTA5MWZmZDk3NjY2NTc4ZmVhMmNkMjk0Yzg1ZGIwMzVhMDVkMDMzNg==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTUzNjdjMTQ1NmI5NmNiYjdlYTdkNmVhNWJlMzVkNjMzYjEwMGY0MjdlNDk5
|
10
|
+
NzQwYzU5ODZkNmIxYTM2N2I5MWRhMjM3OGYwODExYzJhZmQ4ZWZmZWZmZjA4
|
11
|
+
Yzg3NjI4NDc5M2YwYjA0N2ZiYjZkZDQ3NjBiNmNmYjZiOGFhNDk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Zjk3ZGJmZmI4YjA3OTljMjBkNmU2ZDBmNjJlNzgwNjE4ZGJmZGI0NDEwNzQy
|
14
|
+
YjFiMzE1MDgyNWRmNzE0Mjc5ZjYyMzcxYTg2YWQ3OWY3MTg2OWY2ZWM0NjEw
|
15
|
+
OGI4MjUzYjU1MTlhMzVlZDdlZmJjNjYwNGQ0NmEyZDMyOTc0NDE=
|
data/README.md
CHANGED
@@ -9,18 +9,20 @@
|
|
9
9
|
>
|
10
10
|
> —Arakawa and Madeline Gins
|
11
11
|
|
12
|
-
**Immanence** is a DSL for handling web requests in Ruby, built on top of Rack. To execute routes it calculates the [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance) between incoming requests and routes defined
|
12
|
+
**Immanence** is a DSL for handling web requests in Ruby, built on top of Rack. To execute routes it calculates the [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance) between incoming requests and routes defined through the DSL then executes the most likely candidate. *Something will always be executed.* Objects are rendered by calling `→` (alias `render`) with the object to be rendered as the argument. Object responses are encoded as JSON. Incoming JSON is automatically parsed and available in as the `input` object.
|
13
13
|
|
14
|
-
|
14
|
+
What does it mean to discard transparent precision in favor of immanent promiscuity?
|
15
15
|
|
16
16
|
```ruby
|
17
|
-
|
17
|
+
# encoding: UTF-8
|
18
|
+
|
19
|
+
class Application < Immanent::Control
|
18
20
|
route :get, "/fields/:id" do
|
19
|
-
|
21
|
+
→ Field.find(params[:id])
|
20
22
|
end
|
21
23
|
|
22
24
|
route :post, "/fields" do
|
23
|
-
|
25
|
+
→ Field.create(input)
|
24
26
|
end
|
25
27
|
end
|
26
28
|
```
|
data/Rakefile
CHANGED
@@ -4,3 +4,12 @@ desc "Open an irb session preloaded with this library"
|
|
4
4
|
task :console do
|
5
5
|
sh "irb -rubygems -I lib -r immanence.rb"
|
6
6
|
end
|
7
|
+
|
8
|
+
desc "Run specs"
|
9
|
+
task :spec do
|
10
|
+
require "rspec/core/rake_task"
|
11
|
+
|
12
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
13
|
+
spec.rspec_opts = %w{--colour --format progress}
|
14
|
+
end
|
15
|
+
end
|
data/lib/immanence.rb
CHANGED
@@ -8,77 +8,98 @@ require "core_ext/hash"
|
|
8
8
|
require "core_ext/object"
|
9
9
|
|
10
10
|
module Immanence
|
11
|
-
class Request
|
11
|
+
class Request
|
12
|
+
attr_reader :input
|
13
|
+
|
14
|
+
def initialize(request, input)
|
15
|
+
@__request__ = request
|
16
|
+
@input = input
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method, *args, &block)
|
20
|
+
@__request__.send(method, *args, &block)
|
21
|
+
end
|
22
|
+
end # Request
|
12
23
|
|
13
24
|
class Control
|
14
25
|
I = λ { |i| Oj.load(i) }
|
15
26
|
O = λ { |o| Oj.dump(o, mode: :compat) }
|
16
27
|
|
17
|
-
LEVENSHTEIN = λ
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
28
|
+
LEVENSHTEIN = λ do |a, b|
|
29
|
+
[(0..a.size).to_a].tap { |mx|
|
30
|
+
(1..b.size).each do |j|
|
31
|
+
mx << [j] + [0] * (a.size)
|
32
|
+
end
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
+
(1..b.size).each do |i|
|
35
|
+
(1..a.size).each do |j|
|
36
|
+
if a[j-1] == b[i-1]
|
37
|
+
mx[i][j] = mx[i-1][j-1]
|
38
|
+
else
|
39
|
+
mx[i][j] = [
|
40
|
+
mx[i-1][j],
|
41
|
+
mx[i][j-1],
|
42
|
+
mx[i-1][j-1]
|
43
|
+
].min + 1
|
44
|
+
end
|
34
45
|
end
|
35
46
|
end
|
36
|
-
|
37
|
-
|
38
|
-
mx[-1][-1]
|
39
|
-
}
|
47
|
+
}[-1][-1]
|
48
|
+
end
|
40
49
|
|
41
50
|
class << self
|
42
|
-
|
43
|
-
body = O[body]
|
51
|
+
alias_method :delegate_to, :send
|
44
52
|
|
45
|
-
|
53
|
+
# Convenience methods
|
54
|
+
def request() @request end
|
55
|
+
def input() request.input end
|
56
|
+
def params() ascertain(receiver, request.path).reverse_merge!(request.params) end
|
57
|
+
|
58
|
+
# Naive implementation
|
59
|
+
def before(&blk) yield end
|
46
60
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
})
|
61
|
+
# Interface with Rack
|
62
|
+
def call(env)
|
63
|
+
@request = Request.new(Rack::Request.new(env), I[env["rack.input"]])
|
51
64
|
|
52
|
-
|
65
|
+
delegate_to receiver
|
66
|
+
rescue => ε
|
67
|
+
→ ({ error: ε }),
|
68
|
+
{ status: 500, headers:
|
69
|
+
{ "X-Message" => "[...] from a problem to the accidents that condition and resolve it." } }
|
53
70
|
end
|
54
71
|
|
72
|
+
# Define routes in the application
|
55
73
|
def route(verb, path, &blk)
|
56
74
|
meta_def(conjugate(verb, path)) { instance_eval &blk }
|
57
75
|
end
|
58
76
|
|
59
|
-
|
60
|
-
|
61
|
-
|
77
|
+
# Render responses
|
78
|
+
def render(body=:ok, options={})
|
79
|
+
options.reverse_merge!({ status: 200 })
|
62
80
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
81
|
+
options[:headers] ||= {}
|
82
|
+
options[:headers].reverse_merge!({
|
83
|
+
"Content-Type" => "text/json", "X-Framework" => "Immanence" })
|
84
|
+
|
85
|
+
Rack::Response.new(O[body], options[:status], options[:headers]).finish
|
67
86
|
end
|
68
87
|
|
88
|
+
alias_method :→, :render
|
89
|
+
|
69
90
|
private
|
70
91
|
|
71
92
|
def conjugate(verb, path) # :nodoc:
|
72
93
|
"immanent_#{verb}_#{path}"
|
73
94
|
end
|
74
95
|
|
75
|
-
# @return [Hash] Hash of request
|
96
|
+
# @return [Hash] Hash of parameters gleaned from request signature
|
76
97
|
def ascertain(method, path)
|
77
98
|
[method.to_s.gsub(/immanent_\w*_/, ""), path].
|
78
99
|
|
79
100
|
map { |path| path.split("/")[1..-1] }.
|
80
101
|
let { |x, y| x.zip(y) }.
|
81
|
-
select { |x,
|
102
|
+
select { |x, _| x[0] == ":" }.
|
82
103
|
map { |x, y| { x[1..-1] => y } }.
|
83
104
|
|
84
105
|
reduce({}, :merge).
|
@@ -88,9 +109,11 @@ module Immanence
|
|
88
109
|
# @return [String] most likely candidate method to invoke based on incoming route
|
89
110
|
def receiver
|
90
111
|
@receiver ||= methods.grep(/immanent_/).map { |method|
|
91
|
-
{ method: method, Δ: LEVENSHTEIN[method, conjugate(
|
112
|
+
{ method: method, Δ: LEVENSHTEIN[method, conjugate(request.request_method, request.path)] }
|
92
113
|
}.min_by { |x| x[:Δ] }[:method]
|
93
114
|
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
115
|
+
end # self
|
116
|
+
end # Control
|
117
|
+
end # Immanence
|
118
|
+
|
119
|
+
Immanent = Immanence
|
data/lib/immanence/version.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
|
4
|
+
|
5
|
+
describe "Immanent" do
|
6
|
+
before do
|
7
|
+
class Application < Immanent::Control
|
8
|
+
route :get, "/resource/:id" do
|
9
|
+
render ({ no: :future })
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should calculate the Levenshtein difference between two strings (0)" do
|
15
|
+
Immanent::Control::LEVENSHTEIN["kitten", "sitten"].should eq 1
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should calculate the Levenshtein difference between two strings (1)" do
|
19
|
+
Immanent::Control::LEVENSHTEIN["sitten", "sittin"].should eq 1
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should calculate the Levenshtein difference between two strings (2)" do
|
23
|
+
Immanent::Control::LEVENSHTEIN["sittin", "sitting"].should eq 1
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should conjugate a verb and path into a method name" do
|
27
|
+
Immanent::Control.send(:conjugate, :get, "/resource/:id").should eq "immanent_get_/resource/:id"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should extract parameters out of the request path" do
|
31
|
+
Immanent::Control.send(:ascertain, "immanent_get_/resource/:id", "/resource/1000").should eq({ id: "1000" })
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be able to extract multiple parameters out of the request path" do
|
35
|
+
Immanent::Control.send(:ascertain, "immanent_get_/resource/:resource_id/child/:id", "/resource/1000/child/10").should eq({ resource_id: "1000", id: "10" })
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should provide a DSL for defining routes" do
|
39
|
+
Application.methods.include?(:"immanent_get_/resource/:id").should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have a default response" do
|
43
|
+
Application.render[0].should eq(Rack::Response.new("\"ok\"").finish[0])
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should respond with the route definition, a JSON string" do
|
47
|
+
Application.send("immanent_get_/resource/:id").last.body.should eq(["{\"no\":\"future\"}"])
|
48
|
+
end
|
49
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: immanence
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dzucconi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -97,6 +97,8 @@ files:
|
|
97
97
|
- lib/core_ext/object.rb
|
98
98
|
- lib/immanence.rb
|
99
99
|
- lib/immanence/version.rb
|
100
|
+
- spec/immanence_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
100
102
|
homepage: http://github.com/dzucconi/immanence
|
101
103
|
licenses:
|
102
104
|
- CC0
|
@@ -121,5 +123,7 @@ rubygems_version: 2.0.6
|
|
121
123
|
signing_key:
|
122
124
|
specification_version: 4
|
123
125
|
summary: A framework
|
124
|
-
test_files:
|
126
|
+
test_files:
|
127
|
+
- spec/immanence_spec.rb
|
128
|
+
- spec/spec_helper.rb
|
125
129
|
has_rdoc:
|