cameleon 0.1.0
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/.document +5 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.md +105 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/cameleon +6 -0
- data/cameleon.gemspec +106 -0
- data/lib/cameleon/action.rb +29 -0
- data/lib/cameleon/app.rb +13 -0
- data/lib/cameleon/cli/gallery.rb +18 -0
- data/lib/cameleon/cli/generate.rb +30 -0
- data/lib/cameleon/cli/new.rb +15 -0
- data/lib/cameleon/cli/server.rb +34 -0
- data/lib/cameleon/cli.rb +66 -0
- data/lib/cameleon/renderer.rb +99 -0
- data/lib/cameleon.rb +45 -0
- data/template/gallery/response/gallery/erb/default.txt +2 -0
- data/template/gallery/response/gallery/json/_switch.rb +15 -0
- data/template/gallery/response/gallery/json/bar.json +1 -0
- data/template/gallery/response/gallery/json/default.json +1 -0
- data/template/gallery/response/gallery/json/foo.json +1 -0
- data/template/gallery/response/gallery/params/_switch.rb +10 -0
- data/template/gallery/response/gallery/params/bar.txt +1 -0
- data/template/gallery/response/gallery/params/default.txt +1 -0
- data/template/gallery/response/gallery/params/foo.txt +1 -0
- data/template/gallery/response/gallery/rest/_switch.rb +16 -0
- data/template/gallery/response/gallery/rest/delete.txt +1 -0
- data/template/gallery/response/gallery/rest/get.txt +1 -0
- data/template/gallery/response/gallery/rest/put_or_post.txt +1 -0
- data/template/gallery/response/gallery/simple/default.txt +1 -0
- data/template/gallery/response/gallery/xml/_switch.rb +18 -0
- data/template/gallery/response/gallery/xml/bar.xml +1 -0
- data/template/gallery/response/gallery/xml/default.xml +1 -0
- data/template/gallery/response/gallery/xml/foo.xml +1 -0
- data/template/generate/_switch.rb +5 -0
- data/template/generate/default +1 -0
- data/template/new/cameleon.yml +1 -0
- data/template/new/response/_root/_switch.rb +8 -0
- data/template/new/response/_root/default +3 -0
- data/test/helper.rb +18 -0
- data/test/test_cameleon.rb +4 -0
- metadata +193 -0
data/.document
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 daixque
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
Cameleon
|
2
|
+
=======================================
|
3
|
+
|
4
|
+
Cameleon (not Chameleon!) is HTTP mock server framework based on Rack. You can easily create HTTP server for mockup or stub of external system for your application.
|
5
|
+
|
6
|
+
All you have to do to create a new interface is simply make directory and put text file into the directory.
|
7
|
+
|
8
|
+
Features:
|
9
|
+
|
10
|
+
- Simple API for "_switch.rb" (for selecting response file)
|
11
|
+
- Communicate in JSON, XML or any format over HTTP
|
12
|
+
- Easy to create RESTful API
|
13
|
+
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
You can install Cameleon using RubyGems as below:
|
17
|
+
|
18
|
+
$ gem install cameleon
|
19
|
+
|
20
|
+
|
21
|
+
## Getting started
|
22
|
+
First, create a new Cameleon project.
|
23
|
+
|
24
|
+
$ cameleon new your_project_name.
|
25
|
+
|
26
|
+
Then move the directory now you created, and launch cameleon server.
|
27
|
+
|
28
|
+
$ cd your_project_name
|
29
|
+
$ cameleon server
|
30
|
+
|
31
|
+
OK, your server is now running. Test your server using curl.
|
32
|
+
|
33
|
+
$ curl http://localhost:9292
|
34
|
+
Hey, I am cameleon!
|
35
|
+
Edit response folder to change response whatever you want.
|
36
|
+
see README.md more detail.
|
37
|
+
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
### creating HTTP interface
|
41
|
+
Think about creating HTTP interface such like below:
|
42
|
+
|
43
|
+
- URL: /path/to/interface
|
44
|
+
- response: "ok"
|
45
|
+
|
46
|
+
Then all you have to do are below:
|
47
|
+
|
48
|
+
$ mkdir -p response/path/to/interface
|
49
|
+
$ cd response/path/to/interface
|
50
|
+
$ echo "ok" > default.txt
|
51
|
+
|
52
|
+
Test the interface:
|
53
|
+
|
54
|
+
$ curl http://localhost:9292/path/to/interface
|
55
|
+
ok
|
56
|
+
|
57
|
+
### generate command
|
58
|
+
Or simply, you can create a interface using "cameleon generate" command.
|
59
|
+
If you want to create a new interface "/path/to/foo", type:
|
60
|
+
|
61
|
+
$ cameleon generate path/to/foo
|
62
|
+
|
63
|
+
and test it.
|
64
|
+
|
65
|
+
$ curl http://localhost:9292/path/to/foo
|
66
|
+
edit me: response/path/to/foo/default
|
67
|
+
|
68
|
+
So edit the file as you need.
|
69
|
+
|
70
|
+
### _switch.rb
|
71
|
+
If you want to change the response by HTTP request, you shold create "_switch.rb" in your response directory.
|
72
|
+
|
73
|
+
Below shows a sample of "_switch.rb".
|
74
|
+
|
75
|
+
# you can access URL parameters by 'params'
|
76
|
+
case params[:key]
|
77
|
+
when "foo"
|
78
|
+
# curl http://localhost:9292/gallery/params?key=foo
|
79
|
+
render "foo.txt"
|
80
|
+
when "bar"
|
81
|
+
# You can also use POST or PUT. See 'rest' more about hadling HTTP methods.
|
82
|
+
# curl -XPOST http://localhost:9292/gallery/params -d"key=bar"
|
83
|
+
render "bar.txt"
|
84
|
+
end
|
85
|
+
|
86
|
+
# if else, render "default" (any extention acceptable) file.
|
87
|
+
|
88
|
+
|
89
|
+
## Gallery
|
90
|
+
You can get various samples using "cameleon gallery" command.
|
91
|
+
$ cd YOUR_CAMELEON_HOME
|
92
|
+
$ cameleon gallery
|
93
|
+
|
94
|
+
Check out response/gallery directory and "_switch.rb" to know usage of APIs.
|
95
|
+
|
96
|
+
|
97
|
+
## License
|
98
|
+
Cameleon is released under the MIT license.
|
99
|
+
|
100
|
+
|
101
|
+
## Copyright
|
102
|
+
Copyright (c) 2011 [daisuke sugimori][1] ([@daixque][2]).
|
103
|
+
|
104
|
+
[1]: http://opentechnica.blogspot.com/
|
105
|
+
[2]: http://twitter.com/daixque
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "cameleon"
|
18
|
+
gem.homepage = "http://github.com/daixque/cameleon"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Cameleon is HTTP mock server framework.}
|
21
|
+
gem.description = %Q{Cameleon is HTTP mock server framework based on Rack. You can easily create HTTP server for mockup or stub of external system for your application.}
|
22
|
+
gem.email = "daixque@gmail.com"
|
23
|
+
gem.authors = ["daixque"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "cameleon #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/cameleon
ADDED
data/cameleon.gemspec
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{cameleon}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = [%q{daixque}]
|
12
|
+
s.date = %q{2011-09-11}
|
13
|
+
s.description = %q{Cameleon is HTTP mock server framework based on Rack. You can easily create HTTP server for mockup or stub of external system for your application.}
|
14
|
+
s.email = %q{daixque@gmail.com}
|
15
|
+
s.executables = [%q{cameleon}]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE.txt",
|
18
|
+
"README.md"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".document",
|
22
|
+
"Gemfile",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.md",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"bin/cameleon",
|
28
|
+
"cameleon.gemspec",
|
29
|
+
"lib/cameleon.rb",
|
30
|
+
"lib/cameleon/action.rb",
|
31
|
+
"lib/cameleon/app.rb",
|
32
|
+
"lib/cameleon/cli.rb",
|
33
|
+
"lib/cameleon/cli/gallery.rb",
|
34
|
+
"lib/cameleon/cli/generate.rb",
|
35
|
+
"lib/cameleon/cli/new.rb",
|
36
|
+
"lib/cameleon/cli/server.rb",
|
37
|
+
"lib/cameleon/renderer.rb",
|
38
|
+
"template/gallery/response/gallery/erb/default.txt",
|
39
|
+
"template/gallery/response/gallery/json/_switch.rb",
|
40
|
+
"template/gallery/response/gallery/json/bar.json",
|
41
|
+
"template/gallery/response/gallery/json/default.json",
|
42
|
+
"template/gallery/response/gallery/json/foo.json",
|
43
|
+
"template/gallery/response/gallery/params/_switch.rb",
|
44
|
+
"template/gallery/response/gallery/params/bar.txt",
|
45
|
+
"template/gallery/response/gallery/params/default.txt",
|
46
|
+
"template/gallery/response/gallery/params/foo.txt",
|
47
|
+
"template/gallery/response/gallery/rest/_switch.rb",
|
48
|
+
"template/gallery/response/gallery/rest/delete.txt",
|
49
|
+
"template/gallery/response/gallery/rest/get.txt",
|
50
|
+
"template/gallery/response/gallery/rest/put_or_post.txt",
|
51
|
+
"template/gallery/response/gallery/simple/default.txt",
|
52
|
+
"template/gallery/response/gallery/xml/_switch.rb",
|
53
|
+
"template/gallery/response/gallery/xml/bar.xml",
|
54
|
+
"template/gallery/response/gallery/xml/default.xml",
|
55
|
+
"template/gallery/response/gallery/xml/foo.xml",
|
56
|
+
"template/generate/_switch.rb",
|
57
|
+
"template/generate/default",
|
58
|
+
"template/new/cameleon.yml",
|
59
|
+
"template/new/response/_root/_switch.rb",
|
60
|
+
"template/new/response/_root/default",
|
61
|
+
"test/helper.rb",
|
62
|
+
"test/test_cameleon.rb"
|
63
|
+
]
|
64
|
+
s.homepage = %q{http://github.com/daixque/cameleon}
|
65
|
+
s.licenses = [%q{MIT}]
|
66
|
+
s.require_paths = [%q{lib}]
|
67
|
+
s.rubygems_version = %q{1.8.6}
|
68
|
+
s.summary = %q{Cameleon is HTTP mock server framework.}
|
69
|
+
|
70
|
+
if s.respond_to? :specification_version then
|
71
|
+
s.specification_version = 3
|
72
|
+
|
73
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
74
|
+
s.add_runtime_dependency(%q<erubis>, [">= 0"])
|
75
|
+
s.add_runtime_dependency(%q<rack>, [">= 0"])
|
76
|
+
s.add_runtime_dependency(%q<hashie>, [">= 0"])
|
77
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
78
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
79
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
80
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
81
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
82
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
83
|
+
else
|
84
|
+
s.add_dependency(%q<erubis>, [">= 0"])
|
85
|
+
s.add_dependency(%q<rack>, [">= 0"])
|
86
|
+
s.add_dependency(%q<hashie>, [">= 0"])
|
87
|
+
s.add_dependency(%q<json>, [">= 0"])
|
88
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
89
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
90
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
91
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
92
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
93
|
+
end
|
94
|
+
else
|
95
|
+
s.add_dependency(%q<erubis>, [">= 0"])
|
96
|
+
s.add_dependency(%q<rack>, [">= 0"])
|
97
|
+
s.add_dependency(%q<hashie>, [">= 0"])
|
98
|
+
s.add_dependency(%q<json>, [">= 0"])
|
99
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
100
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
101
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
102
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
103
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'erubis'
|
3
|
+
|
4
|
+
class Cameleon
|
5
|
+
class Action
|
6
|
+
def find_default_file
|
7
|
+
Dir.entries(@base_path).find { |f| f =~ /^default\./ }
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle(req)
|
11
|
+
@base_path = File.join("response", req.path)
|
12
|
+
if req.path == "/"
|
13
|
+
@base_path += "_root"
|
14
|
+
end
|
15
|
+
@params = req.params
|
16
|
+
@body = req.body.read
|
17
|
+
switch_filepath = File.join @base_path, "_switch.rb"
|
18
|
+
renderer = nil
|
19
|
+
if !File.exists?(@base_path)
|
20
|
+
return [404, {}, ["dir not found: #{@base_path}"]]
|
21
|
+
elsif File.exists?(switch_filepath)
|
22
|
+
renderer = Renderer.run_switch(@base_path, req, switch_filepath)
|
23
|
+
else
|
24
|
+
renderer = Renderer.render_file(@base_path, req)
|
25
|
+
end
|
26
|
+
renderer.build_response
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/cameleon/app.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
class Cameleon
|
4
|
+
class App
|
5
|
+
def call(env)
|
6
|
+
Cameleon.import File.join(Cameleon.root, "lib/cameleon/action.rb")
|
7
|
+
Cameleon.import File.join(Cameleon.root, "lib/cameleon/renderer.rb")
|
8
|
+
action = Cameleon::Action.new
|
9
|
+
req = Rack::Request.new(env)
|
10
|
+
action.handle(req)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'cameleon'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
def new
|
7
|
+
unless Cameleon.config
|
8
|
+
$stderr.puts "not cameleon home"
|
9
|
+
exit(1)
|
10
|
+
end
|
11
|
+
|
12
|
+
base_dir = File.join(Cameleon.root, 'template/gallery')
|
13
|
+
Dir.glob("#{base_dir}/*").map do |f|
|
14
|
+
FileUtils.cp_r f, "."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
new
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'cameleon'
|
4
|
+
require 'erubis'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
def generate
|
8
|
+
unless Cameleon.config
|
9
|
+
$stderr.puts "not cameleon home"
|
10
|
+
exit(1)
|
11
|
+
end
|
12
|
+
|
13
|
+
path = ARGV.shift
|
14
|
+
dir_path = File.join "response", path
|
15
|
+
FileUtils.mkdir_p dir_path
|
16
|
+
|
17
|
+
template_dir = File.join Cameleon.root, "/template/generate"
|
18
|
+
Dir.glob("#{template_dir}/*").map do |path|
|
19
|
+
basename = File.basename(path)
|
20
|
+
target_file_path = File.join dir_path, basename
|
21
|
+
src = File.read path
|
22
|
+
erb = Erubis::Eruby.new src
|
23
|
+
body = erb.result(binding)
|
24
|
+
File.open(target_file_path, "w") do |f|
|
25
|
+
f.puts body
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
generate
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'cameleon'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
def new
|
7
|
+
project_name = ARGV.shift
|
8
|
+
FileUtils.mkdir_p project_name
|
9
|
+
base_dir = File.join(Cameleon.root, 'template/new')
|
10
|
+
Dir.glob("#{base_dir}/*").map do |f|
|
11
|
+
FileUtils.cp_r f, project_name
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
new
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'cameleon'
|
4
|
+
require 'hashie'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
def start(config)
|
8
|
+
version = ">= 0"
|
9
|
+
|
10
|
+
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
|
11
|
+
version = $1
|
12
|
+
ARGV.shift
|
13
|
+
end
|
14
|
+
|
15
|
+
gem 'rack', version
|
16
|
+
require 'rack'
|
17
|
+
require 'rack/builder'
|
18
|
+
require 'rack/handler/webrick'
|
19
|
+
app = Rack::Builder.new {
|
20
|
+
use Rack::Chunked
|
21
|
+
run Cameleon::App.new
|
22
|
+
}
|
23
|
+
trap(:INT) {
|
24
|
+
Rack::Handler::WEBrick.shutdown
|
25
|
+
}
|
26
|
+
Rack::Handler::WEBrick.run app, :Port => (config.port || 9292)
|
27
|
+
end
|
28
|
+
|
29
|
+
config = Cameleon.config
|
30
|
+
unless config
|
31
|
+
$stderr.puts "[ERROR] cameleon.yml is not found."
|
32
|
+
exit(1)
|
33
|
+
end
|
34
|
+
start config
|
data/lib/cameleon/cli.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# command line interface for cameleon
|
3
|
+
|
4
|
+
require 'cameleon'
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
def parse_options(argv)
|
8
|
+
OptionParser.new { |opt|
|
9
|
+
opt.on("-v", "--version") {
|
10
|
+
version = File.read "#{Cameleon.root}/VERSION"
|
11
|
+
puts "cameleon #{version}"
|
12
|
+
exit(0)
|
13
|
+
}
|
14
|
+
opt.on("-h", "--help") {
|
15
|
+
usage
|
16
|
+
exit(0)
|
17
|
+
}
|
18
|
+
opt.parse! argv
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def usage
|
23
|
+
puts usage_text = <<-"USAGE"
|
24
|
+
Cameleon - HTTP mock server framework.
|
25
|
+
|
26
|
+
Usage:
|
27
|
+
cameleon [option] command [args]
|
28
|
+
|
29
|
+
Commands:
|
30
|
+
new: create new dummy application
|
31
|
+
server: launch server
|
32
|
+
generate path: generate scaffold for path
|
33
|
+
|
34
|
+
Options:
|
35
|
+
-v: show version
|
36
|
+
USAGE
|
37
|
+
end
|
38
|
+
|
39
|
+
def run
|
40
|
+
aliases = {
|
41
|
+
's' => 'server',
|
42
|
+
'g' => 'generate'
|
43
|
+
}
|
44
|
+
|
45
|
+
parse_options ARGV
|
46
|
+
|
47
|
+
command = ARGV.shift
|
48
|
+
command = aliases[command] || command
|
49
|
+
case command
|
50
|
+
when 'server'
|
51
|
+
require 'cameleon/cli/server'
|
52
|
+
when 'new'
|
53
|
+
require 'cameleon/cli/new'
|
54
|
+
when 'generate'
|
55
|
+
require 'cameleon/cli/generate'
|
56
|
+
when 'gallery'
|
57
|
+
require 'cameleon/cli/gallery'
|
58
|
+
when 'help'
|
59
|
+
usage
|
60
|
+
else
|
61
|
+
puts "unknown command: #{command}."
|
62
|
+
puts "'cameleon help' for usage."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
run
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'hashie'
|
3
|
+
require 'json'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
class Cameleon
|
7
|
+
class Renderer
|
8
|
+
class << self
|
9
|
+
def run_switch(base_path, req, switch_path)
|
10
|
+
switch_src = File.read switch_path
|
11
|
+
Renderer.new(base_path, req).__eval_switch(switch_src)
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_file(base_path, req, filename = nil)
|
15
|
+
catch(:read) {
|
16
|
+
Renderer.new(base_path, req).render(filename)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(base_path, req)
|
22
|
+
@base_path = base_path
|
23
|
+
@status_code = 200
|
24
|
+
@headers = {
|
25
|
+
"Content-Type" => "text/plain"
|
26
|
+
}
|
27
|
+
@req = req
|
28
|
+
@params = Hashie::Mash.new req.params
|
29
|
+
req.body.rewind
|
30
|
+
@body = req.body.read
|
31
|
+
@method = req.env["REQUEST_METHOD"]
|
32
|
+
end
|
33
|
+
|
34
|
+
def __eval_switch(switch_src)
|
35
|
+
catch(:read) {
|
36
|
+
eval switch_src
|
37
|
+
render find_default_file
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def params
|
42
|
+
@params
|
43
|
+
end
|
44
|
+
|
45
|
+
def json_body
|
46
|
+
@json_body || @json_body = Hashie::Mash.new(JSON.parse(@body))
|
47
|
+
end
|
48
|
+
|
49
|
+
def xml_body
|
50
|
+
@xml_body || @xml_body = Nokogiri::XML::Document.parse(@body)
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_response
|
54
|
+
[@status_code, @headers, [@body]]
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_header(name, value)
|
58
|
+
@headers[name] = value
|
59
|
+
end
|
60
|
+
|
61
|
+
def status_code(code)
|
62
|
+
@status_code = code
|
63
|
+
end
|
64
|
+
|
65
|
+
def on(*http_methods, &block)
|
66
|
+
if http_methods.map { |m| m.to_s.upcase }.include? @method
|
67
|
+
yield
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def get(&block)
|
72
|
+
on(:get, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
def put(&block)
|
76
|
+
on(:put, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def post(&block)
|
80
|
+
on(:post, &block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def delete(&block)
|
84
|
+
on(:delete, &block)
|
85
|
+
end
|
86
|
+
|
87
|
+
def render(filename = nil)
|
88
|
+
filename = find_default_file unless filename
|
89
|
+
src = File.read File.join(@base_path, filename)
|
90
|
+
erb = Erubis::Eruby.new src
|
91
|
+
@body = erb.result(binding)
|
92
|
+
throw :read, self
|
93
|
+
end
|
94
|
+
|
95
|
+
def find_default_file
|
96
|
+
Dir.entries(@base_path).find { |f| f =~ /^default/ }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/cameleon.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'cameleon/app'
|
4
|
+
require 'hashie'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
class Cameleon
|
8
|
+
@@imported = {}
|
9
|
+
@@config = nil
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def root
|
13
|
+
File.join File.dirname(__FILE__), "../"
|
14
|
+
end
|
15
|
+
|
16
|
+
def import(file)
|
17
|
+
raise "file not found" unless File.exists? file
|
18
|
+
crnt_timestamp = File::stat(file).mtime
|
19
|
+
if @@imported.include?(file)
|
20
|
+
prev_timestamp = @@imported[file]
|
21
|
+
if (crnt_timestamp > prev_timestamp)
|
22
|
+
@@imported[file] = crnt_timestamp
|
23
|
+
load(file)
|
24
|
+
return true
|
25
|
+
else
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
else
|
29
|
+
@@imported[file] = crnt_timestamp
|
30
|
+
load(file)
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
end # import
|
34
|
+
|
35
|
+
def config
|
36
|
+
@config ||= begin
|
37
|
+
path = "./cameleon.yml"
|
38
|
+
unless File.exist? path
|
39
|
+
return nil
|
40
|
+
end
|
41
|
+
Hashie::Mash.new YAML.load(File.read(path))
|
42
|
+
end
|
43
|
+
end # config
|
44
|
+
end # class methods
|
45
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# set HTTP header
|
2
|
+
set_header "Content-Type", "application/json"
|
3
|
+
|
4
|
+
# you can access POST body as json by 'json_body'
|
5
|
+
case json_body.query
|
6
|
+
when "foo"
|
7
|
+
# curl -XPOST http://localhost:9292/gallery/json -d"{\"query\":\"foo\"}"
|
8
|
+
render "foo.json"
|
9
|
+
when "bar"
|
10
|
+
# curl -XPOST http://localhost:9292/gallery/json -d"{\"query\":\"bar\"}"
|
11
|
+
render "bar.json"
|
12
|
+
end
|
13
|
+
|
14
|
+
# if nothing to match, use 404 HTTP Status Code and render default.json.
|
15
|
+
status_code 404
|
@@ -0,0 +1 @@
|
|
1
|
+
{"result": "bar.json"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"result": "404 not found (default.json)"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"result": "foo.json"}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# you can access URL parameters by 'params'
|
2
|
+
case params[:key]
|
3
|
+
when "foo"
|
4
|
+
# curl http://localhost:9292/gallery/params?key=foo
|
5
|
+
render "foo.txt"
|
6
|
+
when "bar"
|
7
|
+
# You can also use POST or PUT. See 'rest' more about hadling HTTP methods.
|
8
|
+
# curl -XPOST http://localhost:9292/gallery/params -d"key=bar"
|
9
|
+
render "bar.txt"
|
10
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
bar.txt
|
@@ -0,0 +1 @@
|
|
1
|
+
This is default.txt.
|
@@ -0,0 +1 @@
|
|
1
|
+
foo.txt
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# 'on' method handles HTTP Methods.
|
2
|
+
on(:get) {
|
3
|
+
# curl -XGET "http://localhost:9292/gallery/rest"
|
4
|
+
render "get.txt"
|
5
|
+
}
|
6
|
+
on(:put, :post) {
|
7
|
+
# curl -XPUT "http://localhost:9292/gallery/rest" -d=""
|
8
|
+
render "put_or_post.txt"
|
9
|
+
}
|
10
|
+
|
11
|
+
# or simply 'get', 'put', 'post' and 'delete' methods are available for same purpose.
|
12
|
+
# this is same as on(:delete) {}
|
13
|
+
delete {
|
14
|
+
# curl -XDELETE "http://localhost:9292/gallery/rest"
|
15
|
+
render "delete.txt"
|
16
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
delete.txt
|
@@ -0,0 +1 @@
|
|
1
|
+
get.txt
|
@@ -0,0 +1 @@
|
|
1
|
+
put_or_post.txt
|
@@ -0,0 +1 @@
|
|
1
|
+
This is default.txt.
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# set HTTP header
|
2
|
+
set_header "Content-Type", "application/xml"
|
3
|
+
|
4
|
+
# you can access HTTP body as XML document by 'xml_body'.
|
5
|
+
# xml_body is Nokogiri::XML::Document object.
|
6
|
+
# See Nokogiri website for more info.
|
7
|
+
# http://nokogiri.org/
|
8
|
+
case xml_body.xpath("/root/query").first.text
|
9
|
+
when "foo"
|
10
|
+
# curl -XPOST http://localhost:9292/gallery/xml -d"<root><query>foo</query></root>"
|
11
|
+
render "foo.xml"
|
12
|
+
when "bar"
|
13
|
+
# curl -XPOST http://localhost:9292/gallery/xml -d"<root><query>bar</query></root>"
|
14
|
+
render "bar.xml"
|
15
|
+
end
|
16
|
+
|
17
|
+
# if nothing to match, use 404 HTTP Status Code and render default.xml.
|
18
|
+
status_code 404
|
@@ -0,0 +1 @@
|
|
1
|
+
<result>bar.xml</result>
|
@@ -0,0 +1 @@
|
|
1
|
+
<result>404 not found (dafault.xml)</result>
|
@@ -0,0 +1 @@
|
|
1
|
+
<result>foo.xml</result>
|
@@ -0,0 +1 @@
|
|
1
|
+
edit me: <%= target_file_path %>
|
@@ -0,0 +1 @@
|
|
1
|
+
port: 9292
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'cameleon'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cameleon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- daixque
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-11 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: erubis
|
16
|
+
requirement: &2156026340 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156026340
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rack
|
27
|
+
requirement: &2156019320 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2156019320
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: hashie
|
38
|
+
requirement: &2156012980 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2156012980
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: json
|
49
|
+
requirement: &2156005480 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2156005480
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: nokogiri
|
60
|
+
requirement: &2156000260 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2156000260
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: shoulda
|
71
|
+
requirement: &2155995580 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2155995580
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: bundler
|
82
|
+
requirement: &2155991700 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 1.0.0
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *2155991700
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: jeweler
|
93
|
+
requirement: &2155982160 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ~>
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 1.6.4
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *2155982160
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: rcov
|
104
|
+
requirement: &2155978480 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *2155978480
|
113
|
+
description: Cameleon is HTTP mock server framework based on Rack. You can easily
|
114
|
+
create HTTP server for mockup or stub of external system for your application.
|
115
|
+
email: daixque@gmail.com
|
116
|
+
executables:
|
117
|
+
- cameleon
|
118
|
+
extensions: []
|
119
|
+
extra_rdoc_files:
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
files:
|
123
|
+
- .document
|
124
|
+
- Gemfile
|
125
|
+
- LICENSE.txt
|
126
|
+
- README.md
|
127
|
+
- Rakefile
|
128
|
+
- VERSION
|
129
|
+
- bin/cameleon
|
130
|
+
- cameleon.gemspec
|
131
|
+
- lib/cameleon.rb
|
132
|
+
- lib/cameleon/action.rb
|
133
|
+
- lib/cameleon/app.rb
|
134
|
+
- lib/cameleon/cli.rb
|
135
|
+
- lib/cameleon/cli/gallery.rb
|
136
|
+
- lib/cameleon/cli/generate.rb
|
137
|
+
- lib/cameleon/cli/new.rb
|
138
|
+
- lib/cameleon/cli/server.rb
|
139
|
+
- lib/cameleon/renderer.rb
|
140
|
+
- template/gallery/response/gallery/erb/default.txt
|
141
|
+
- template/gallery/response/gallery/json/_switch.rb
|
142
|
+
- template/gallery/response/gallery/json/bar.json
|
143
|
+
- template/gallery/response/gallery/json/default.json
|
144
|
+
- template/gallery/response/gallery/json/foo.json
|
145
|
+
- template/gallery/response/gallery/params/_switch.rb
|
146
|
+
- template/gallery/response/gallery/params/bar.txt
|
147
|
+
- template/gallery/response/gallery/params/default.txt
|
148
|
+
- template/gallery/response/gallery/params/foo.txt
|
149
|
+
- template/gallery/response/gallery/rest/_switch.rb
|
150
|
+
- template/gallery/response/gallery/rest/delete.txt
|
151
|
+
- template/gallery/response/gallery/rest/get.txt
|
152
|
+
- template/gallery/response/gallery/rest/put_or_post.txt
|
153
|
+
- template/gallery/response/gallery/simple/default.txt
|
154
|
+
- template/gallery/response/gallery/xml/_switch.rb
|
155
|
+
- template/gallery/response/gallery/xml/bar.xml
|
156
|
+
- template/gallery/response/gallery/xml/default.xml
|
157
|
+
- template/gallery/response/gallery/xml/foo.xml
|
158
|
+
- template/generate/_switch.rb
|
159
|
+
- template/generate/default
|
160
|
+
- template/new/cameleon.yml
|
161
|
+
- template/new/response/_root/_switch.rb
|
162
|
+
- template/new/response/_root/default
|
163
|
+
- test/helper.rb
|
164
|
+
- test/test_cameleon.rb
|
165
|
+
homepage: http://github.com/daixque/cameleon
|
166
|
+
licenses:
|
167
|
+
- MIT
|
168
|
+
post_install_message:
|
169
|
+
rdoc_options: []
|
170
|
+
require_paths:
|
171
|
+
- lib
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
none: false
|
174
|
+
requirements:
|
175
|
+
- - ! '>='
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
segments:
|
179
|
+
- 0
|
180
|
+
hash: -2425352503709104828
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
|
+
none: false
|
183
|
+
requirements:
|
184
|
+
- - ! '>='
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
requirements: []
|
188
|
+
rubyforge_project:
|
189
|
+
rubygems_version: 1.8.6
|
190
|
+
signing_key:
|
191
|
+
specification_version: 3
|
192
|
+
summary: Cameleon is HTTP mock server framework.
|
193
|
+
test_files: []
|