auser-butterfly 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -9,8 +9,11 @@ examples/example.json
9
9
  examples/example.yml
10
10
  lib/butterfly.rb
11
11
  lib/butterfly/adaptor_base.rb
12
+ lib/butterfly/adaptors/favicon_adaptor.rb
12
13
  lib/butterfly/adaptors/json_file_adaptor.rb
13
14
  lib/butterfly/adaptors/yaml_file_adaptor.rb
15
+ lib/butterfly/client.rb
16
+ lib/butterfly/core/hash.rb
14
17
  lib/butterfly/core/string.rb
15
18
  lib/butterfly/default.rb
16
19
  lib/butterfly/request.rb
@@ -19,6 +22,9 @@ lib/butterfly/server.rb
19
22
  script/console
20
23
  script/destroy
21
24
  script/generate
25
+ test/test_adapter_base.rb
22
26
  test/test_butterfly_request.rb
27
+ test/test_butterfly_response.rb
23
28
  test/test_butterfly_server.rb
29
+ test/test_default.rb
24
30
  test/test_helper.rb
data/butterfly.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{butterfly}
5
- s.version = "0.0.2"
5
+ s.version = "0.0.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ari Lerner"]
9
- s.date = %q{2009-04-03}
9
+ s.date = %q{2009-04-06}
10
10
  s.default_executable = %q{flutter}
11
11
  s.description = %q{An HTTP mini server to query against modular adaptors}
12
12
  s.email = ["arilerner@mac.com"]
13
13
  s.executables = ["flutter"]
14
14
  s.extra_rdoc_files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc"]
15
- s.files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "bin/flutter", "butterfly.gemspec", "examples/example.json", "examples/example.yml", "lib/butterfly.rb", "lib/butterfly/adaptor_base.rb", "lib/butterfly/adaptors/json_file_adaptor.rb", "lib/butterfly/adaptors/yaml_file_adaptor.rb", "lib/butterfly/core/string.rb", "lib/butterfly/default.rb", "lib/butterfly/request.rb", "lib/butterfly/response.rb", "lib/butterfly/server.rb", "script/console", "script/destroy", "script/generate", "test/test_butterfly_request.rb", "test/test_butterfly_server.rb", "test/test_helper.rb"]
15
+ s.files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "bin/flutter", "butterfly.gemspec", "examples/example.json", "examples/example.yml", "lib/butterfly.rb", "lib/butterfly/adaptor_base.rb", "lib/butterfly/adaptors/favicon_adaptor.rb", "lib/butterfly/adaptors/json_file_adaptor.rb", "lib/butterfly/adaptors/yaml_file_adaptor.rb", "lib/butterfly/client.rb", "lib/butterfly/core/hash.rb", "lib/butterfly/core/string.rb", "lib/butterfly/default.rb", "lib/butterfly/request.rb", "lib/butterfly/response.rb", "lib/butterfly/server.rb", "script/console", "script/destroy", "script/generate", "test/test_adapter_base.rb", "test/test_butterfly_request.rb", "test/test_butterfly_response.rb", "test/test_butterfly_server.rb", "test/test_default.rb", "test/test_helper.rb"]
16
16
  s.has_rdoc = true
17
17
  s.homepage = %q{http://blog.xnot.org}
18
18
  s.post_install_message = %q{PostInstall.txt}
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.rubyforge_project = %q{butterfly}
22
22
  s.rubygems_version = %q{1.3.1}
23
23
  s.summary = %q{An HTTP mini server to query against modular adaptors}
24
- s.test_files = ["test/test_butterfly_request.rb", "test/test_butterfly_server.rb", "test/test_helper.rb"]
24
+ s.test_files = ["test/test_adapter_base.rb", "test/test_butterfly_request.rb", "test/test_butterfly_response.rb", "test/test_butterfly_server.rb", "test/test_default.rb", "test/test_helper.rb"]
25
25
 
26
26
  if s.respond_to? :specification_version then
27
27
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -1 +1 @@
1
- {"server" : {"name" : "maggie", "winner" : "false", "poolparty" : {"the":"boss"}}}
1
+ {"server" : {"name" : "maggie", "winner" : "false", "poolparty" : {"the":"popsd"}}}
data/lib/butterfly.rb CHANGED
@@ -1,34 +1,27 @@
1
1
  $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
- module Butterfly
5
- VERSION = '0.0.2' unless Butterfly.const_defined?("VERSION")
6
-
7
- def self.reload!
8
- @reloading = true
9
- butterfly_file = __FILE__
10
- $LOADED_FEATURES.delete(butterfly_file)
11
- ::Kernel.load butterfly_file
12
- @reloading = false
13
- end
14
- end
15
-
16
- class Hash
17
- def method_missing(m,*a,&block)
18
- if has_key?(m)
19
- self[m]
20
- else
21
- super
22
- end
23
- end
24
- end
25
-
26
- %w(rubygems thin dslify).each do |lib|
4
+ %w(rubygems thin dslify rack/cache).each do |lib|
27
5
  require lib
28
6
  end
29
7
 
30
- %w(string).each {|lib| require "#{File.dirname(__FILE__)}/butterfly/core/#{lib}" }
8
+ LOADED_FILES = []
31
9
 
32
- %w(default adaptor_base response request server).each do |lib|
33
- require "#{File.dirname(__FILE__)}/butterfly/#{lib}"
10
+ [
11
+ "core/string", "core/hash", "reloadable",
12
+ "default", "adaptor_base", "response", "request", "server"
13
+ ].map {|lib| require "#{File.dirname(__FILE__)}/butterfly/#{lib}" }
14
+
15
+ module Butterfly
16
+ include Reloadable
17
+
18
+ VERSION = '0.0.3' unless Butterfly.const_defined?("VERSION")
19
+
20
+ def self.register_adaptor *files
21
+ files.each {|f| require_reloadable_files f }
22
+ end
23
+
24
+ def self.reload!
25
+ Butterfly.reload_files!
26
+ end
34
27
  end
@@ -1,5 +1,14 @@
1
+ =begin rdoc
2
+ Base AdaptorBase.
3
+
4
+ This is the base that adaptors subclass. It contains the 4 methods (get, put, post, delete) that adaptors
5
+ can receive. It also handles the calling for the adaptors. Before it calls, however, it will call update_request!
6
+ which will call reload_data! to give basic caching, which is inherited on data. To gain access to the reload method,
7
+ simply overwrite reload_data! (but be sure to call super)
8
+ =end
1
9
  module Butterfly
2
10
  class AdaptorBase
11
+ attr_reader :data
3
12
 
4
13
  def get(req, resp)
5
14
  raise Exception.new("Your adaptor does not support get")
@@ -31,14 +40,17 @@ module Butterfly
31
40
  env["REQUEST_URI"].gsub(/\//, '')
32
41
  end
33
42
  def update_request!
34
- reload! if (Time.now.to_i - last_loaded_at >= @time_til_stale)
43
+ reload_data! if (Time.now.to_i - last_loaded_at >= @time_til_stale)
35
44
  end
36
45
  def last_loaded_at
37
46
  @last_loaded_at ||= Time.now.to_i
38
47
  end
39
- def reload!
48
+ def reload_data!
40
49
  @last_loaded_at = Time.now.to_i
41
50
  end
51
+ def data
52
+ @data ||= reload_data!
53
+ end
42
54
  end
43
55
  end
44
56
 
@@ -0,0 +1,15 @@
1
+ =begin rdoc
2
+ Just a favicon adaptor so we can handle favicon requests. Not that we'll ever need to
3
+ =end
4
+ module Butterfly
5
+ class FaviconAdaptor < AdaptorBase
6
+
7
+ def initialize(o={})
8
+ super
9
+ end
10
+ def get(req, resp)
11
+ ""
12
+ end
13
+
14
+ end
15
+ end
@@ -8,24 +8,36 @@ module Butterfly
8
8
  super
9
9
  end
10
10
  def get(req, resp)
11
- if data.has_key?(req.params[0].to_s)
12
- body = "", current_data = data
13
- req.params.each do |param|
14
- current_data = current_data[param.to_s]
11
+ if req.params
12
+ if data.has_key?(req.params[0].to_s)
13
+ body = "", current_data = data
14
+ req.params.each do |param|
15
+ current_data = current_data[param.to_s]
16
+ end
17
+ current_data
18
+ else
19
+ resp.fail!
20
+ "Not found"
15
21
  end
16
- current_data
17
22
  else
18
- resp.fail!
19
- "Not found"
23
+ data
20
24
  end
21
25
  end
22
26
 
27
+ def post(req, resp)
28
+ # @data = req.post_content
29
+ # File.open(@file, "w+") do |f|
30
+ #
31
+ # end
32
+ req.post_content
33
+ end
34
+
23
35
  private
24
36
 
25
37
  def data
26
- @data ||= reload!
38
+ @data ||= reload_data!
27
39
  end
28
- def reload!
40
+ def reload_data!
29
41
  super
30
42
  @data = JSON.parse(open(@file).read)
31
43
  end
@@ -23,9 +23,9 @@ module Butterfly
23
23
  private
24
24
 
25
25
  def data
26
- @data ||= reload!
26
+ @data ||= reload_data!
27
27
  end
28
- def reload!
28
+ def reload_data!
29
29
  super
30
30
  @data = YAML::load(open(@file).read)
31
31
  end
@@ -0,0 +1,21 @@
1
+ require "net/http"
2
+
3
+ module Butterfly
4
+ class Client
5
+
6
+ def self.get_from(host, port, uri)
7
+ resp, data = Net::HTTP.new(host, port).get(uri)
8
+ data
9
+ end
10
+
11
+ def self.post_to(host, port, uri, data={})
12
+ end
13
+
14
+ def self.put_to(host, port, uri, data={})
15
+ end
16
+
17
+ def self.delete_from(host, port, uri, data={})
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ # So we can call methods directory on the hash object
2
+ # rather than having to call [] on it.
3
+ class Hash
4
+ def method_missing(m,*a,&block)
5
+ if has_key?(m)
6
+ self[m]
7
+ else
8
+ super
9
+ end
10
+ end
11
+ end
@@ -1,19 +1,21 @@
1
1
  module Butterfly
2
2
  class Default
3
- include Dslify
4
3
 
5
- default_options(
6
- :host => "localhost",
7
- :port => 8081,
8
- :time_til_stale => 10, # 10 seconds between cache updates
9
- :adaptor => "JsonFile",
10
- :adaptor_opts => {
11
- :file => "#{File.dirname(__FILE__)}/../../examples/example"
4
+ def self.default_options
5
+ @default_options ||= {
6
+ :host => "0.0.0.0",
7
+ :port => 8081,
8
+ :time_til_stale => 10, # 10 seconds between cache updates
9
+ :adaptor => "JsonFile",
10
+ :env => :development,
11
+ :adaptor_opts => {
12
+ :file => "#{File.dirname(__FILE__)}/../../examples/example"
13
+ }
12
14
  }
13
- )
15
+ end
14
16
 
15
- def self.method_missing(m,*a,&block)
16
- default_options.include?(m) ? default_options[m] : super
17
+ def self.method_missing m, *a, &block
18
+ default_options.has_key?(m) ? default_options[m] : super
17
19
  end
18
20
 
19
21
  end
@@ -5,7 +5,13 @@ module Butterfly
5
5
  @env = env
6
6
  end
7
7
  def route_param
8
- @route_param ||= params.shift
8
+ @route_param ||= params.empty? ? nil : params.shift
9
+ end
10
+ def post_data
11
+ @post_data ||= env["rack.input"]
12
+ end
13
+ def post_content
14
+ @post_content ||= post_data.read
9
15
  end
10
16
  def params
11
17
  @params ||= env["REQUEST_URI"].split("?")[0].split(".")[0].split("/").reject {|a| a.empty? }.map {|a| a.to_sym }
@@ -14,7 +20,7 @@ module Butterfly
14
20
  env["REQUEST_METHOD"].downcase.to_sym
15
21
  end
16
22
  def request_type
17
- env["REQUEST_URI"].split(".")[-1]
23
+ env["REQUEST_URI"].split(".")[-1] rescue env["CONTENT_TYPE"] || nil
18
24
  end
19
25
  end
20
26
  end
@@ -1,16 +1,17 @@
1
1
  module Butterfly
2
2
  class Server
3
- attr_reader :app, :host, :port
3
+ attr_reader :app, :host, :port, :env
4
4
  attr_accessor :adaptor_name
5
5
  def initialize(opts={})
6
6
  @host = opts.delete(:host) || Default.host
7
7
  @port = opts.delete(:port) || Default.port
8
+ @env = opts.delete(:env) || Default.env
8
9
  @adaptor_opts = Default.default_options[:adaptor_opts].merge(opts)
9
10
  @app = self
10
11
  end
11
12
 
12
13
  def start!
13
- Thin::Server.start(@host, @port, app)
14
+ at_exit {Thin::Server.start(@host, @port, app)}
14
15
  end
15
16
 
16
17
  def reload!
@@ -22,22 +23,29 @@ module Butterfly
22
23
  end
23
24
 
24
25
  def should_reload?
25
- true
26
+ @env == :development
26
27
  end
27
28
 
28
29
  def call(env)
29
30
  reload! if should_reload?
30
-
31
31
  @request = Request.new env
32
32
  @response = Response.new @request
33
33
 
34
- body = get_adaptor(@request.route_param).send(:handle_call, @request, @response) rescue "Error"
35
-
34
+ body = begin
35
+ get_adaptor(@request.route_param).send(:handle_call, @request, @response)
36
+ rescue Exception => e
37
+ @response.fail!
38
+ "Boom"
39
+ end
36
40
  @response.return!(body)
37
41
  end
38
42
 
39
43
  def get_adaptor(p=Default.adaptor)
40
- @adaptor ||= Butterfly.const_get("#{p.to_s.camel_case}Adaptor").new(@adaptor_opts)
44
+ adaptors[p] ||= Butterfly.const_get("#{p.to_s.camel_case}Adaptor").new(@adaptor_opts) #rescue raise "Error: undefined adaptor for #{@request.route_param}"
45
+ end
46
+
47
+ def adaptors
48
+ @adaptors ||= {}
41
49
  end
42
50
  end
43
51
  end
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestAdapterBase < Test::Unit::TestCase
4
+ context "adaptor_base" do
5
+ before do
6
+ @ab = Butterfly::AdaptorBase.new
7
+ @env = {"REQUEST_URL" => "/"}
8
+ @response = Object.new
9
+ end
10
+ it "should raise an exception if there is no get defined" do
11
+ assert_raise Exception do; @ab.get(@env, @response) end
12
+ end
13
+ it "should raise an exception if there is no post defined" do
14
+ assert_raise Exception do; @ab.post(@env, @response) end
15
+ end
16
+ it "should raise an exception if there is no delete defined" do
17
+ assert_raise Exception do; @ab.delete(@env, @response) end
18
+ end
19
+ it "should raise an exception if there is no put defined" do
20
+ assert_raise Exception do; @ab.put(@env, @response) end
21
+ end
22
+ end
23
+ end
@@ -20,5 +20,27 @@ class TestButterflyRequest < Test::Unit::TestCase
20
20
  it "should not explode with a ?" do
21
21
  Butterfly::Request.new(@env.merge("REQUEST_URI" => "/server/item/two?pop=dance")).params.should == [:server, :item, :two]
22
22
  end
23
+ it "should pull out the post data when post_data is sent" do
24
+ Butterfly::Request.new(@env.merge("rack.input" => "fly away")).post_data.should == "fly away"
25
+ end
26
+ it "should pull out the post data param to map the response" do
27
+ @req = Butterfly::Request.new(@env.merge("REQUEST_URI" => "/server/item"))
28
+ @req.route_param.should == :server
29
+ @req.params.include?(:server).should == false
30
+ end
31
+ context "request type" do
32
+ it "should be :get when REQUEST_METHOD == GET" do
33
+ Butterfly::Request.new(@env.merge("REQUEST_METHOD" => "GET")).request_method.should == :get
34
+ end
35
+ it "should be :get when REQUEST_METHOD == POST" do
36
+ Butterfly::Request.new(@env.merge("REQUEST_METHOD" => "POST")).request_method.should == :post
37
+ end
38
+ it "should be :get when REQUEST_METHOD == PUT" do
39
+ Butterfly::Request.new(@env.merge("REQUEST_METHOD" => "PUT")).request_method.should == :put
40
+ end
41
+ it "should be :get when REQUEST_METHOD == DELETE" do
42
+ Butterfly::Request.new(@env.merge("REQUEST_METHOD" => "DELETE")).request_method.should == :delete
43
+ end
44
+ end
23
45
  end
24
46
  end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestButterflyResponse < Test::Unit::TestCase
4
+ context "response" do
5
+ before do
6
+ @env = {
7
+ "REQUEST_URI" => "/.json",
8
+ "REQUEST_METHOD" => "get"
9
+ }
10
+ @request = Butterfly::Request.new @env
11
+ @response = Butterfly::Response.new @request
12
+ end
13
+ it "should have headers, status and a body" do
14
+ @response.headers.should == {}
15
+ @response.status.should == 200
16
+ @response.body.should == nil
17
+ end
18
+ it "should add the response header on a json request" do
19
+ @response.prepare_headers.should == {"ContentType" => "application/json"}
20
+ end
21
+ it "should return an Array on to the response to return to Rack" do
22
+ @response.return!("hi").class.should == Array
23
+ end
24
+ it "should return a rack request (json)" do
25
+ req = Butterfly::Request.new(@env.merge("REQUEST_URI" => "/index.json"))
26
+ resp = Butterfly::Response.new req
27
+ resp.return!("hi").should == [200, {"ContentType" => "application/json"}, "\"hi\""]
28
+ end
29
+ it "should return a rack request (text)" do
30
+ req = Butterfly::Request.new(@env.merge("REQUEST_URI" => "/"))
31
+ resp = Butterfly::Response.new req
32
+ resp.return!("hi").should == [200, {"ContentType" => "text/plain"}, "hi"]
33
+ end
34
+ it "should be able to add headers" do
35
+ @response.add_header("foo", "bar")
36
+ @response.headers.should === {"foo" => "bar"}
37
+ end
38
+ it "should return a 404 when there is a fail!" do
39
+ @response.fail!
40
+ @response.return!("hi").should == [404, {"ContentType" => "application/json"}, "\"hi\""]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestDefault < Test::Unit::TestCase
4
+ include Butterfly
5
+ context "Default" do
6
+
7
+ should "be able to have a port on the class" do
8
+ Default.port.should == 8081
9
+ end
10
+
11
+ end
12
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: auser-butterfly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ari Lerner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-03 00:00:00 -07:00
12
+ date: 2009-04-06 00:00:00 -07:00
13
13
  default_executable: flutter
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -56,8 +56,11 @@ files:
56
56
  - examples/example.yml
57
57
  - lib/butterfly.rb
58
58
  - lib/butterfly/adaptor_base.rb
59
+ - lib/butterfly/adaptors/favicon_adaptor.rb
59
60
  - lib/butterfly/adaptors/json_file_adaptor.rb
60
61
  - lib/butterfly/adaptors/yaml_file_adaptor.rb
62
+ - lib/butterfly/client.rb
63
+ - lib/butterfly/core/hash.rb
61
64
  - lib/butterfly/core/string.rb
62
65
  - lib/butterfly/default.rb
63
66
  - lib/butterfly/request.rb
@@ -66,8 +69,11 @@ files:
66
69
  - script/console
67
70
  - script/destroy
68
71
  - script/generate
72
+ - test/test_adapter_base.rb
69
73
  - test/test_butterfly_request.rb
74
+ - test/test_butterfly_response.rb
70
75
  - test/test_butterfly_server.rb
76
+ - test/test_default.rb
71
77
  - test/test_helper.rb
72
78
  has_rdoc: true
73
79
  homepage: http://blog.xnot.org
@@ -97,6 +103,9 @@ signing_key:
97
103
  specification_version: 2
98
104
  summary: An HTTP mini server to query against modular adaptors
99
105
  test_files:
106
+ - test/test_adapter_base.rb
100
107
  - test/test_butterfly_request.rb
108
+ - test/test_butterfly_response.rb
101
109
  - test/test_butterfly_server.rb
110
+ - test/test_default.rb
102
111
  - test/test_helper.rb