auser-butterfly 0.0.2 → 0.0.3

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