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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MDcyOTJhNmQ0NTc5MDU4MjhkYTVmMGJiNTRmZjU5MWU4NTRmNzY3ZQ==
4
+ MTZkMWFhOGNhODAxOGMyNzYyNTcwNDBhMmEzZWVjNTc3ZTk4ODJlYQ==
5
5
  data.tar.gz: !binary |-
6
- MDJkZmNlNGQ1ZDQ5MDJiMjRhMTIxMjAyNTdmMGM0NWU0ZmYyN2RlOQ==
6
+ YTA5MWZmZDk3NjY2NTc4ZmVhMmNkMjk0Yzg1ZGIwMzVhMDVkMDMzNg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- N2IzMTc4Mjg4Y2Y4MDM3MTBjYzYyOTA0MGI3NDZkN2RkOWE4NWFmYjcxNzNk
10
- ZDFmMzQyNmUzYzQ0ZDQ2ZGIxYTE1MjliZDZiZjYyNGUwYjhiNDA3Mzg1Y2E1
11
- MmIwODhhMzI2MTliZTgwYjE0NGU0MmNiNjNhZDNkZjQ0YzMxYjY=
9
+ MTUzNjdjMTQ1NmI5NmNiYjdlYTdkNmVhNWJlMzVkNjMzYjEwMGY0MjdlNDk5
10
+ NzQwYzU5ODZkNmIxYTM2N2I5MWRhMjM3OGYwODExYzJhZmQ4ZWZmZWZmZjA4
11
+ Yzg3NjI4NDc5M2YwYjA0N2ZiYjZkZDQ3NjBiNmNmYjZiOGFhNDk=
12
12
  data.tar.gz: !binary |-
13
- NjE0MGRkN2I2NDhjZGRjNmU4YzM1ODVjNDYzMWIwNDAzNmUxN2M1NjliMjE2
14
- MmNjYzNkMWQ5ZWE0ZTg0NzRkOTQyYmJhYTRhYmZkY2NkZjk3ZmQ3M2YwOTIx
15
- ZDQwZDIzYmY2MTI2OWY1NDJlOGUyNTJjNTQwZDQ4NDc2NTJkNzU=
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 in the DSL then executes the most likely candidate. *Something will always be executed.* Objects are rendered by calling `>>` on `self` with the object to be rendered as the argument. Objects are serialized into JSON via Oj. Incoming JSON is automatically parsed and available in the `@request` object.
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
- This is less a useful piece of software and more of a stylistic exercise.
14
+ What does it mean to discard transparent precision in favor of immanent promiscuity?
15
15
 
16
16
  ```ruby
17
- class Application < Immanence::Control
17
+ # encoding: UTF-8
18
+
19
+ class Application < Immanent::Control
18
20
  route :get, "/fields/:id" do
19
- self >> Field.find(@params[:id])
21
+ Field.find(params[:id])
20
22
  end
21
23
 
22
24
  route :post, "/fields" do
23
- self >> Field.create(@request.input)
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
@@ -8,77 +8,98 @@ require "core_ext/hash"
8
8
  require "core_ext/object"
9
9
 
10
10
  module Immanence
11
- class Request < Struct.new(:verb, :path, :input); end
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 = λ { |a, b|
18
- mx = [(0..a.size).to_a]
19
-
20
- (1..b.size).each do |j|
21
- mx << [j] + [0] * (a.size)
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
- (1..b.size).each do |i|
25
- (1..a.size).each do |j|
26
- if a[j-1] == b[i-1]
27
- mx[i][j] = mx[i-1][j-1]
28
- else
29
- mx[i][j] = [
30
- mx[i-1][j],
31
- mx[i][j-1],
32
- mx[i-1][j-1]
33
- ].min + 1
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
- end
37
-
38
- mx[-1][-1]
39
- }
47
+ }[-1][-1]
48
+ end
40
49
 
41
50
  class << self
42
- def >>(body=:ok, options={}, headers={})
43
- body = O[body]
51
+ alias_method :delegate_to, :send
44
52
 
45
- options.reverse_merge!({ status: 200 })
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
- headers.reverse_merge!({
48
- "Content-Type" => "text/json",
49
- "Content-Length" => ("#{body.size}" rescue "0")
50
- })
61
+ # Interface with Rack
62
+ def call(env)
63
+ @request = Request.new(Rack::Request.new(env), I[env["rack.input"]])
51
64
 
52
- [options[:status], headers, [body]]
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
- def call(e)
60
- @request = Request.new e["REQUEST_METHOD"].downcase, e["PATH_INFO"], I[e["rack.input"].read]
61
- @params = ascertain receiver, @request.path
77
+ # Render responses
78
+ def render(body=:ok, options={})
79
+ options.reverse_merge!({ status: 200 })
62
80
 
63
- send receiver
64
- rescue => ε
65
- # [...] from a problem to the accidents that condition and resolve it.
66
- self >> { error: ε }
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 parameters
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, y| x[0] == ":" }.
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(@request.verb, @request.path)] }
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
@@ -1,3 +1,3 @@
1
1
  module Immanence
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -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
@@ -0,0 +1,3 @@
1
+ require "rspec"
2
+
3
+ require "./lib/immanence"
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.0.2
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-07-25 00:00:00.000000000 Z
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: