apirunner 0.3.5 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.5
1
+ 0.3.6
data/apirunner.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{apirunner}
8
- s.version = "0.3.5"
8
+ s.version = "0.3.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["jan@moviepilot.com"]
12
- s.date = %q{2010-10-07}
12
+ s.date = %q{2010-10-12}
13
13
  s.description = %q{apirunner is a testsuite to query your RESTful JSON API and match response with your defined expectations}
14
14
  s.email = %q{developers@moviepilot.com}
15
15
  s.extra_rdoc_files = [
@@ -45,7 +45,6 @@ Gem::Specification.new do |s|
45
45
  "lib/apirunner.rb",
46
46
  "lib/apirunner/railtie.rb",
47
47
  "lib/checker.rb",
48
- "lib/core_extensions.rb",
49
48
  "lib/expectation_matcher.rb",
50
49
  "lib/http_client.rb",
51
50
  "lib/plugins/plug01_response_json_syntax_checker.rb",
@@ -53,12 +52,16 @@ Gem::Specification.new do |s|
53
52
  "lib/plugins/plug03_response_header_checker.rb",
54
53
  "lib/plugins/plug04_response_body_checker.rb",
55
54
  "lib/result.rb",
55
+ "lib/string_ext.rb",
56
56
  "lib/tasks/api.rake",
57
57
  "lib/testcase.rb",
58
58
  "spec/.rspec",
59
+ "spec/api_configuration_spec.rb",
59
60
  "spec/api_runner_spec.rb",
61
+ "spec/checker_spec.rb",
60
62
  "spec/expectation_matcher_spec.rb",
61
63
  "spec/http_client_spec.rb",
64
+ "spec/result_spec.rb",
62
65
  "spec/spec_helper.rb"
63
66
  ]
64
67
  s.homepage = %q{http://github.com/moviepilot/apirunner}
@@ -66,9 +69,12 @@ Gem::Specification.new do |s|
66
69
  s.rubygems_version = %q{1.3.7}
67
70
  s.summary = %q{one-line summary of your gem}
68
71
  s.test_files = [
72
+ "spec/api_configuration_spec.rb",
69
73
  "spec/api_runner_spec.rb",
74
+ "spec/checker_spec.rb",
70
75
  "spec/expectation_matcher_spec.rb",
71
76
  "spec/http_client_spec.rb",
77
+ "spec/result_spec.rb",
72
78
  "spec/spec_helper.rb"
73
79
  ]
74
80
 
data/lib/api_runner.rb CHANGED
@@ -1,22 +1,25 @@
1
1
  class ApiRunner
2
2
  require 'yaml'
3
+ require 'string_ext' if not String.respond_to?(:underscore)
3
4
  require 'expectation_matcher'
4
5
  require 'http_client'
5
6
  require 'api_configuration'
6
7
  require 'testcase'
7
- require 'core_extensions'
8
- include CoreExtensions
8
+ require 'string_ext'
9
+
10
+ require 'JSON'
9
11
 
10
12
  CONFIG_FILE = "config/api_runner.yml"
11
13
  SPEC_PATH = "test/api_runner/"
12
14
  EXCLUDES_FILE = "test/api_runner/excludes.yml"
13
15
 
14
16
  # initializes the object, loads environment, build base_uri
15
- def initialize(env)
17
+ def initialize(env, performance=nil)
16
18
  @spec = []
17
19
  @results = []
18
20
  @excludes = []
19
21
  @configuration = ApiConfiguration.new(YAML.load_file(self.class.config_file), env)
22
+ @configuration.verbosity = "performance" if performance
20
23
  load_excludes(env)
21
24
  load_url_spec
22
25
  @http_client = HttpClient.new(@configuration.protocol, @configuration.host, @configuration.port, @configuration.namespace)
@@ -148,4 +151,3 @@ class ApiRunner
148
151
  EXCLUDES_FILE
149
152
  end
150
153
  end
151
-
data/lib/apirunner.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  APIRUNNER_ROOT=File.dirname(__FILE__) + "/.."
2
2
  require 'api_runner'
3
+ require 'string_ext'
3
4
  module Apirunner
4
5
  require 'apirunner/railtie' if defined?(Rails)
5
6
  end
data/lib/checker.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  class Checker
2
-
3
2
  @@children = []
4
3
 
5
4
  def initialize(testcase, response, excludes=nil)
@@ -27,26 +26,6 @@ class Checker
27
26
  @@children << child
28
27
  end
29
28
 
30
- # recursively parses the tree and returns a set of relative pathes
31
- # that can be used to match the both trees leafs
32
- def matcher_pathes_from(node, pathes = nil)
33
- pathes ||= []
34
- if not node.children.blank?
35
- node.children.each do |sub_node|
36
- matcher_pathes_from(sub_node, pathes)
37
- end
38
- else
39
- pathes << relative_path(node.parent.path)
40
- end
41
- pathes
42
- end
43
-
44
- # returns relative path for matching the target tree of the response body
45
- # explicit array adressing is replaced by *
46
- def relative_path(path)
47
- path.gsub(/\/([^\/]+)\[\d+\]\//i,"/*/")
48
- end
49
-
50
29
  # returns true if given attributes is an excluded item that does not have to be evaluated in this environment
51
30
  def excluded?(item)
52
31
  @excludes.include?(item)
@@ -71,7 +50,7 @@ class Checker
71
50
  # parses output into JSON object
72
51
  def valid_json?(response_body)
73
52
  # responses may be nil, return true then
74
- return true if response_body.blank?
53
+ return true if response_body.nil? or response_body == {} or response_body == "" or response_body == " "
75
54
  # returns true if given response is valid json, else false
76
55
  JSON.parse(response_body.to_s) rescue false
77
56
  end
data/lib/http_client.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  class HttpClient
2
2
  require 'net/http'
3
+ require "cgi"
4
+ require "benchmark"
3
5
 
4
6
  def initialize(protocol, host, port, namespace)
5
7
  @http = Net::HTTP.new(host, port)
@@ -10,53 +12,56 @@ class HttpClient
10
12
  end
11
13
 
12
14
  def send_request(method, resource, headers=nil, data=nil, params=nil)
13
- build_response(self.send(method.to_s.downcase, headers, resource, data, params))
15
+ runtime, response = self.send(method.to_s.downcase, headers, resource, data, params)
16
+ build_response(response, runtime, method, resource, params)
14
17
  end
15
18
 
16
19
  protected
17
20
 
18
21
  # returns struct containing response.code, headers, body and message
19
22
  # this is only for easily interfaceing another http client
20
- def build_response(raw_response)
21
- response_struct = Struct.new(:code, :message, :headers, :body)
23
+ def build_response(raw_response, runtime, method, resource, params)
24
+ end_time = Time.now.usec
25
+ response_struct = Struct.new(:code, :message, :headers, :body, :runtime, :fully_qualified_path)
22
26
  response = response_struct.new
23
27
  response.code = raw_response.code
24
28
  response.message = raw_response.message
25
29
  response.body = raw_response.body
26
- response.headers = JSON.parse(raw_response.header.to_json) rescue nil
30
+ response.headers = JSON.parse(raw_response.headers.to_json) rescue ""
31
+ response.runtime = runtime
32
+ response.fully_qualified_path = (method == "GET" ? build_uri(resource, params).request_uri : resource_path(resource))
27
33
  response
28
34
  end
29
35
 
30
36
  # sends GET request and returns response
31
37
  def get(headers, resource, data, params)
32
38
  request = Net::HTTP::Get.new(build_uri(resource, params).request_uri, initheader = headers)
33
- @http.request(request)
39
+ return Benchmark.realtime{ @response = @http.request(request) }, @response
34
40
  end
35
41
 
36
42
  # sends PUT request and returns response
37
43
  def put(headers, resource, data, params)
38
44
  request = Net::HTTP::Put.new(resource_path(resource), initheader = headers)
39
45
  request.body = data.to_json
40
- @http.request(request)
46
+ return Benchmark.realtime { @response = @http.request(request) }, @response
41
47
  end
42
48
 
43
49
  # sends POST request and returns response
44
50
  def post(headers, resource, data, params)
45
51
  request = Net::HTTP::Post.new(resource_path(resource), initheader = headers)
46
52
  request.body = data.to_json
47
- @http.request(request)
53
+ return Benchmark.realtime{ @response = @http.request(request) }, @response
48
54
  end
49
55
 
50
56
  # sends DELETE request and returns response
51
57
  def delete(headers, resource, data, params)
52
58
  request = Net::HTTP::Delete.new(resource_path(resource), initheader = headers)
53
- @http.request(request)
59
+ return Benchmark.realtime{ @response = @http.request(request) }, @response
54
60
  end
55
61
 
56
62
  # redefines the resource path including the namespace
57
63
  def resource_path(resource)
58
64
  @namespace.nil? ? resource : "/" + @namespace + resource
59
- "/" + @namespace + resource
60
65
  end
61
66
 
62
67
  # rebuild a uri in details, so that another protocol, host, port and GET params can be specified, after Net::HTTP was created
@@ -5,7 +5,7 @@ class ResponseJsonSyntaxChecker < Checker
5
5
  result = Result.new(@testcase, @response)
6
6
  if not valid_json?(@response.body)
7
7
  result.succeeded = false
8
- result.error_message = "expected valid JSON in body\n got --#{@response.body[1..400]}--"
8
+ result.error_message = "expected valid JSON in body\n got --#{@response.body[1..400]}-- #{@response.body.class}"
9
9
  end
10
10
  result
11
11
  end
@@ -8,10 +8,11 @@ class ResponseCodeChecker < Checker
8
8
  result.succeeded = false
9
9
  result.error_message = " expected response code --#{@testcase.response_expectation['status_code']}--\n got response code --#{@response.code}--"
10
10
  end
11
- rescue
12
- result.succeeded = false
13
- result.error_message = " unexpected error while parsing testcase/response. Check your testcase format!"
14
- end
11
+ rescue Exception => e
12
+ result.succeeded = false
13
+ result.error_message = " unexpected error while parsing testcase/response. Check your testcase format!"
14
+ result.error_message = "\n\n Exception occured: #{e}"
15
+ end
15
16
  result
16
17
  end
17
18
 
@@ -17,10 +17,11 @@ class ResponseHeaderChecker < Checker
17
17
  end
18
18
  end
19
19
  end unless (@testcase.response_expectation['headers'].nil? or @testcase.response_expectation['headers'].empty?)
20
- rescue
21
- result.succeeded = false
22
- result.error_message = " unexpected error while parsing testcase/response. Check your testcase format!"
23
- end
20
+ rescue Exception => e
21
+ result.succeeded = false
22
+ result.error_message = " unexpected error while parsing testcase/response. Check your testcase format!"
23
+ result.error_message = "\n\nException occured: #{e}"
24
+ end
24
25
  result
25
26
  end
26
27
 
@@ -66,4 +66,26 @@ class ResponseBodyChecker < Checker
66
66
  end
67
67
  result
68
68
  end
69
+
70
+ private
71
+
72
+ # recursively parses the tree and returns a set of relative pathes
73
+ # that can be used to match the both trees leafs
74
+ def matcher_pathes_from(node, pathes = nil)
75
+ pathes ||= []
76
+ if not node.children.blank?
77
+ node.children.each do |sub_node|
78
+ matcher_pathes_from(sub_node, pathes)
79
+ end
80
+ else
81
+ pathes << relative_path(node.parent.path)
82
+ end
83
+ pathes
84
+ end
85
+
86
+ # returns relative path for matching the target tree of the response body
87
+ # explicit array adressing is replaced by *
88
+ def relative_path(path)
89
+ path.gsub(/\/([^\/]+)\[\d+\]\//i,"/*/")
90
+ end
69
91
  end
data/lib/result.rb CHANGED
@@ -42,13 +42,14 @@ class Result
42
42
  # yields a more verbose message in any case and includes a curl command to manually simulate the testcase
43
43
  def verbose_with_curl(index)
44
44
  be_verbose(index)
45
- puts "\n simulate this call with: \"curl TODO\""
45
+ puts("\n simulate this call with: \"curl TODO\"")
46
46
  end
47
47
 
48
48
  # yields the verbose error messages
49
49
  def be_verbose(index)
50
50
  puts "\n#{result_case} (#{index+1})- \"#{@testcase.name}\""
51
51
  puts @error_message
52
+ puts("Request runtime: #{@response.runtime}")
52
53
  puts(" More more more verbosity\n")
53
54
  puts(" request method: #{@testcase.request['method']}")
54
55
  puts(" resource path: #{@testcase.request['path']}")
@@ -64,6 +65,12 @@ class Result
64
65
  puts(" response body: #{JSON.parse(@response.body) rescue nil}")
65
66
  end
66
67
 
68
+ # yields out only performance information
69
+ def performance(index)
70
+ puts "\n#{@testcase.name}\n"
71
+ puts " %-10s %-20s %-8s %s " % ["#{@response.runtime.to_s[0..6]}s", "[#{result_case}]", @testcase.request['method'], @response.fully_qualified_path]
72
+ end
73
+
67
74
  # returns the result case for interpolation in the output message header
68
75
  def result_case
69
76
  if @succeeded
@@ -85,8 +92,8 @@ class Result
85
92
 
86
93
  def ansi_colors(color)
87
94
  case color
88
- when 'green' then ['\033[32m', '\033[0m']
89
- when 'red' then ['\033[31m', '\033[0m']
95
+ when :green then ["\033[32m", "\033[0m"]
96
+ when :red then ["\033[31m", "\033[0m"]
90
97
  else ['','']
91
98
  end
92
99
  end
data/lib/string_ext.rb ADDED
@@ -0,0 +1,23 @@
1
+ class String
2
+ # generates filenames from classnames the rails way
3
+ def underscore
4
+ self.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
5
+ end
6
+
7
+ # opposites underscore defined above
8
+ def camelize(first_letter_in_uppercase = true)
9
+ if first_letter_in_uppercase
10
+ self.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
11
+ else
12
+ self.first + camelize(lower_case_and_underscored_word)[1..-1]
13
+ end
14
+ end
15
+ # # opposites underscore defined above
16
+ # def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
17
+ # if first_letter_in_uppercase
18
+ # lower_case_and_underscored_word.to_s.gsub(/\\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
19
+ # else
20
+ # lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
21
+ # end
22
+ # end
23
+ end
data/lib/tasks/api.rake CHANGED
@@ -4,7 +4,7 @@ rescue
4
4
  end
5
5
  namespace :api do
6
6
  namespace :run do
7
- config.each_key do |env|
7
+ config.delete_if{ |key| key == "general" }.each_key do |env|
8
8
  desc "runs a series of nessecary api calls and parses their response in environment #{env}"
9
9
  task env.to_sym => :environment do
10
10
  puts "Running API tests in environment #{env}"
@@ -14,6 +14,17 @@ namespace :api do
14
14
  end
15
15
  end unless config.nil?
16
16
  end
17
+ namespace:performance do
18
+ config.delete_if{ |key| key == "general" }.each_key do |env|
19
+ desc "runs a series of nessecary api calls for performance measuring and parses their response in environment #{env}"
20
+ task env.to_sym => :environment do
21
+ puts "Running API performance tests in environment #{env}"
22
+ api_runner = ApiRunner.new(env, performance=true)
23
+ api_runner.run
24
+ puts "\nPerformance testrun finished\n\n"
25
+ end
26
+ end unless config.nil?
27
+ end
17
28
  desc "generates configuration and a skeleton for apirunner tests as well as excludes"
18
29
  task :scaffold do
19
30
  TEST_EXAMPLES_PATH="test/api_runner"
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe 'initialize' do
4
+ before(:each) do
5
+ @config_hash = {
6
+ "test" => {
7
+ :a => 1,
8
+ :b => 2,
9
+ :protocol => "http",
10
+ :host => "localhost",
11
+ :port => 3000,
12
+ :namespace => "namespace"
13
+ },
14
+ "general" => {
15
+ "verbosity" => ["verbose", "unused"],
16
+ "priority" => 10
17
+ }
18
+ }
19
+ end
20
+
21
+ it 'should set instance variables for each config key value pair' do
22
+ @a = ApiConfiguration.new(@config_hash, "test")
23
+ @a.instance_variable_get(:@a).should == 1
24
+ @a.instance_variable_get(:@b).should == 2
25
+ @a.instance_variable_get(:@protocol).should == "http"
26
+ @a.instance_variable_get(:@host).should == "localhost"
27
+ @a.instance_variable_get(:@port).should == 3000
28
+ @a.instance_variable_get(:@namespace).should == "namespace"
29
+ end
30
+
31
+ it 'should set verbosity correctly' do
32
+ @a = ApiConfiguration.new(@config_hash, "test")
33
+ @a.instance_variable_get(:@verbosity).should == "verbose"
34
+ end
35
+
36
+ it 'should set priority correctly' do
37
+ @a = ApiConfiguration.new(@config_hash, "test")
38
+ @a.instance_variable_get(:@priority).should == 10
39
+ end
40
+ end
@@ -8,11 +8,20 @@ describe 'apirunner' do
8
8
  @a = ApiRunner.new(:local)
9
9
  end
10
10
  describe 'initialize' do
11
- it 'should fill all instance variables' do
12
- @a.instance_variable_get(:@protocol).should eql "http"
13
- @a.instance_variable_get(:@host).should eql "localhost"
14
- @a.instance_variable_get(:@port).should eql 3000
15
- @a.instance_variable_get(:@namespace).should eql "api1v0"
11
+ it 'should fill all instance variables properly' do
12
+ @a.instance_variable_get(:@spec).should be_a(Array)
13
+ @a.instance_variable_get(:@spec).size.should == 58
14
+ @a.instance_variable_get(:@results).should be_a(Array)
15
+ @a.instance_variable_get(:@results).size.should == 0
16
+ @a.instance_variable_get(:@configuration).should be_a(ApiConfiguration)
17
+ @a.instance_variable_get(:@configuration).host.should == "localhost"
18
+ @a.instance_variable_get(:@configuration).port.should == 3000
19
+ @a.instance_variable_get(:@configuration).protocol.should == "http"
20
+ @a.instance_variable_get(:@configuration).namespace.should == "api1v0"
21
+ @a.instance_variable_get(:@configuration).verbosity.should == "verbose_on_error"
22
+ @a.instance_variable_get(:@configuration).priority.should == 0
23
+ @a.instance_variable_get(:@http_client).should be_a(HttpClient)
24
+ @a.instance_variable_get(:@expectation).should be_a(ExpectationMatcher)
16
25
  end
17
26
  it 'should fill @excludes' do
18
27
  @a.instance_variable_get(:@excludes).should_not be_nil
@@ -24,36 +33,41 @@ describe 'apirunner' do
24
33
  @a.instance_variable_get(:@spec).should be_a(Array)
25
34
  @a.instance_variable_get(:@spec).size.should >= 1
26
35
  end
27
- it 'should instantiate an http client into @http_client' do
28
- @a.instance_variable_get(:@http_client).should be_a(HttpClient)
29
- end
30
- it 'should instantiate an expectation_matcher into @expectation' do
31
- @a.instance_variable_get(:@expectation).should be_a(ExpectationMatcher)
32
- end
33
36
  end
34
37
 
35
38
  describe 'run_tests' do
36
39
  it 'should send a request for every given testcase' do
37
- response_struct = Struct.new(:code, :message, :headers, :body)
38
- response = response_struct.new
39
- response.code = 404
40
- response.message = "Ok"
41
- response.body = {}
42
- response.headers = {}
40
+ pending "TODO"
41
+ response = Result.new({},{})
43
42
  @a.should_receive(:server_is_available?).and_return true
44
43
  @a.should_receive(:send_request).exactly(@a.instance_variable_get(:@spec).size).times.and_return(response)
45
44
  @a.run
46
45
  end
47
- it 'should run a test for every test_type'
48
- it 'should save an error message in @errors if an error occured'
46
+ it 'should save an error message in @errors if an error occured' do
47
+ pending "TODO"
48
+ response = Result.new({},{})
49
+ @a.should_receive(:server_is_available?).and_return true
50
+ @a.should_receive(:send_request).exactly(@a.instance_variable_get(:@spec).size).times.and_return(response)
51
+ @a.run
52
+ @a.instance_variable_get(:@results).should_not be_nil
53
+ @a.instance_variable_get(:@results).size.should_not == 0
54
+ end
49
55
  end
50
56
 
51
57
  describe 'send_request' do
52
- it 'should invoke send_request at the @http_client with the appropiate method, uri and data'
58
+ it "should invoke send_request at the @http_client with appropiate method, path, headers, body and get-parameters" do
59
+ pending "TODO"
60
+ @a.instance_variable_get(:@http_client).should_receive(:send_request).and_return(Result.new({},{}))
61
+ @a.send(:send_request_for,Testcase.new({}))
62
+ end
53
63
  end
54
64
 
55
65
  describe 'target_uri' do
56
- it 'should create a correct target uri from existing instance variables'
66
+ it 'should create a correct target uri from existing instance variables' do
67
+ @a.send(:target_uri).match(@a.instance_variable_get(:@configuration).protocol).should be_true
68
+ @a.send(:target_uri).match(@a.instance_variable_get(:@configuration).host).should be_true
69
+ @a.send(:target_uri).match("://").should be_true
70
+ end
57
71
  end
58
72
 
59
73
  describe 'server_is_available?' do
@@ -0,0 +1,86 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'json'
3
+ require 'nokogiri'
4
+
5
+ describe "Checker" do
6
+ describe "self.available_plugins" do
7
+ it "should return an array of available plugins inheriting from self" do
8
+ Checker.available_plugins.should be_a(Array)
9
+ Checker.available_plugins.size.should_not == 0
10
+ end
11
+ end
12
+ describe "relative_path" do
13
+ it 'should substitute an absolute addressing in a given path' do
14
+ pending "Move me"
15
+ path = "/bla/foo/values[6]/duffy/duck"
16
+ Checker.new({},{}).send(:relative_path, path).should eql "/bla/foo/*/duffy/duck"
17
+ end
18
+ it 'should substitute more than one absolute adressing in a given path' do
19
+ pending "Move me"
20
+ path = "/bla/foo/values[6]/duffy/friends[1]/duck"
21
+ Checker.new({},{}).send(:relative_path, path).should eql "/bla/foo/*/duffy/*/duck"
22
+ end
23
+ it 'should return a string' do
24
+ pending "Move me"
25
+ path = "/bla/foo/values[6]/duffy/friends[1]/duck"
26
+ Checker.new({},{}).send(:relative_path, path).should be_a(String)
27
+ end
28
+ end
29
+ describe "excluded?" do
30
+ it "should return true if a given item is not part of the instances exludes"
31
+ it "should return false if a given item is part of the instances excludes"
32
+ end
33
+ describe "is_regex?" do
34
+ it 'should return true if the given string seems to be a regular expression' do
35
+ string = "/^\d{3}$/"
36
+ Checker.new({},{}).send(:is_regex?, string).should be_true
37
+ end
38
+ it 'should return false if the given string does not seem to be a regular expression' do
39
+ string = "fooz"
40
+ Checker.new({},{}).send(:is_regex?, string).should be_false
41
+ string = "/fooz"
42
+ Checker.new({},{}).send(:is_regex?, string).should be_false
43
+ string = "fooz/"
44
+ Checker.new({},{}).send(:is_regex?, string).should be_false
45
+ end
46
+ end
47
+ describe "regex_matches?" do
48
+ it 'should return true if the given regular expression matches the given value' do
49
+ regex = "^\\d{2}$"
50
+ value = "12"
51
+ Checker.new({},{}).send(:regex_matches?, regex, value).should be_true
52
+ end
53
+ it 'should return false if the giveb reular expression does not match the given value' do
54
+ regex = "^\\d{2}$"
55
+ value = "123"
56
+ Checker.new({},{}).send(:regex_matches?, regex, value).should be_false
57
+ value = "foo"
58
+ Checker.new({},{}).send(:regex_matches?, regex, value).should be_false
59
+ end
60
+ end
61
+ describe "string_matches?" do
62
+ it 'should return true if the given string matches the given value' do
63
+ string = "bar"
64
+ value = "bar"
65
+ Checker.new({},{}).send(:string_matches?, string, value).should be_true
66
+ end
67
+ it 'should return false if the given string does not match the given value' do
68
+ string = "bar"
69
+ value = "foo"
70
+ Checker.new({},{}).send(:string_matches?, string, value).should be_false
71
+ end
72
+ end
73
+ describe "valid_json?" do
74
+ it 'should return true if the given response body consists of valid JSON' do
75
+ validateable = { :foo => "bar" }.to_json
76
+ Checker.new({},{}).send(:valid_json?, validateable).should be_true
77
+ end
78
+ it 'should return true if the given response body is nil' do
79
+ Checker.new({},{}).send(:valid_json?, nil).should be_true
80
+ end
81
+ it 'should return false if the given response body consists of anything else but valid JSON' do
82
+ Checker.new({},{}).send(:valid_json?, "foobar").should be_false
83
+ end
84
+ end
85
+ end
86
+
@@ -1,232 +1,35 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require 'json'
3
- require 'nokogiri'
4
2
 
5
3
  describe 'ExpectationMatcher' do
6
- before(:each) do
7
- @em = ExpectationMatcher.new
8
- end
9
- describe 'regex_matches?' do
10
- it 'should return true if given regex matches the given string' do
11
- ExpectationMatcher.new.send(:regex_matches?, "/^\\d{2}$/", "12").should be_true
12
- end
13
- it 'should return false if the given regex does not match the given string' do
14
- ExpectationMatcher.new.send(:regex_matches?, "/^\\d{2}$/", "133").should be_false
15
- end
16
- end
17
-
18
- describe 'testtypes' do
19
- it 'should return the available testtypes of the class' do
20
- @em.test_types.should eql ([:response_code, :response_body_format, :response_headers, :response_body])
21
- end
22
- it 'should at least return one testtype' do
23
- @em.test_types.size.should >= 1
24
- end
25
- it 'should return an array of symbols' do
26
- @em.test_types.should be_a(Array)
27
- @em.test_types.each do |type|
28
- type.should be_a(Symbol)
29
- end
30
- end
31
- it 'should not return nil' do
32
- @em.test_types.should_not be_nil
33
- end
34
- end
35
-
36
- describe 'check' do
37
- it 'should invoke http client with the given method, response and testcase' do
38
- @em = ExpectationMatcher.new
39
- @em.should_receive(:put)
40
- @em.check(:put, {}, [])
41
- @em.should_receive(:post)
42
- @em.check(:post, {}, [])
43
- @em.should_receive(:get)
44
- @em.check(:get, {}, [])
45
- @em.should_receive(:delete)
46
- @em.check(:delete, {}, [])
47
- end
48
- end
49
-
50
- describe 'response_code' do
51
- it 'should return a struct representing success if the given response code matches the expected one' do
52
- response_struct = Struct.new(:code, :message, :headers, :body)
53
- response = response_struct.new
54
- response.code = 404
55
- testcase = { 'response_expectation' => { 'status_code' => 404 } }
56
- @em.send(:response_code, response, testcase).should be_a(Struct)
57
- @em.send(:response_code, response, testcase).succeeded.should be_true
58
- @em.send(:response_code, response, testcase).error.should be_nil
59
- end
60
- it 'should return a struct representing failure if the given repsonse code does not match the expected one' do
61
- response_struct = Struct.new(:code, :message, :headers, :body)
62
- response = response_struct.new
63
- response.code = 400
64
- testcase = { 'response_expectation' => { 'status_code' => 404 } }
65
- @em.send(:response_code, response, testcase).should be_a(Struct)
66
- @em.send(:response_code, response, testcase).succeeded.should be_false
67
- @em.send(:response_code, response, testcase).error.should_not be_nil
68
- end
69
- end
70
-
71
- describe 'response_body_format' do
72
- before(:each) do
73
- response_struct = Struct.new(:code, :message, :headers, :body)
74
- @response = response_struct.new
75
- end
76
- it 'should return a struct representing success if the given response body is nil, cause this is allowed' do
77
- @response.body = nil
78
- @em.send(:response_body_format, @response, {}).should be_a(Struct)
79
- @em.send(:response_body_format, @response, {}).succeeded.should be_true
80
- @em.send(:response_body_format, @response, {}).error.should be_nil
81
- end
82
- it 'should return the given response body in JSON format, if a valid JSON string is given to check' do
83
- @response.body = {:fooz => "baaz"}.to_json
84
- @em.send(:response_body_format, @response, {}).should be_a(Struct)
85
- @em.send(:response_body_format, @response, {}).succeeded.should be_true
86
- @em.send(:response_body_format, @response, {}).error.should be_nil
87
- end
88
- it 'should not fatal but return false, if the given response body is no valid JSON' do
89
- @response.body = "foozbaz"
90
- @em.send(:response_body_format, @response, {}).should be_a(Struct)
91
- @em.send(:response_body_format, @response, {}).succeeded.should be_false
92
- @em.send(:response_body_format, @response, {}).error.should_not be_nil
93
- end
94
- end
95
-
96
- describe 'response_headers' do
97
- before(:each) do
98
- response_struct = Struct.new(:code, :message, :headers, :body)
99
- @response = response_struct.new
100
- end
101
- it 'should return a struct representing success, if one certain expected header value matches the response header' do
102
- @response.headers = {"content-type"=>["text/html; charset=utf-8"], "cache-control"=>["no-cache"], "x-runtime"=>["0.340116"], "server"=>["WEBrick/1.3.1 (Ruby/1.9.2/2010-08-18)"], "date"=>["Tue, 21 Sep 2010 11:33:05 GMT"], "content-length"=>["149"], "connection"=>["close"], "Last-Modified" => "2010-10-01 23:23:23"}
103
- testcase = { 'response_expectation' => { 'headers' => {"Last-Modified"=>"/.*/"} } }
104
- @em.send(:response_headers, @response, testcase).should be_a(Struct)
105
- @em.send(:response_headers, @response, testcase).succeeded.should be_true
106
- @em.send(:response_headers, @response, testcase).error.should be_nil
107
- end
108
- it 'should return a struct representing success, if more than one expected header values match the ones in the repsonse header' do
109
- pending "TODO: pair this one"
110
- end
111
- it 'should even return a struct representing success if the response header contains more values than the excpected' do
112
- pending "TODO: pair this one"
113
- end
114
- it 'should return a struct representing an error, if one single expected header value does not match the one in response' do
115
- pending "TODO: pair this one"
116
- end
117
- it 'should return a struct representing an error, if one of more expected header values does not match the corresponding one in the response' do
118
- pending "TODO: pair this one"
119
- end
120
- it 'should return a struct representing success, if the expected header is nil - no expectation exists' do
121
- pending "TODO: pair this one"
122
- testcase = { 'response_expectation' => { 'headers' => nil } }
123
- @em.send(:response_headers, @response, testcase).should be_a(Struct)
124
- @em.send(:response_headers, @response, testcase).succeeded.should be_true
125
- @em.send(:response_headers, @response, testcase).error.should be_nil
126
- end
127
- end
128
-
129
- describe 'response_body' do
130
- it 'should check something'
131
- it 'should return a result struct'
132
- end
133
-
134
- describe 'matcher_pathes_from' do
135
- it 'should return pathes to all leaves of a given tree including relative pathes in case of arrays in the JSON' do
136
- xml_tree = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><hash><bla>laber</bla><foo><values type=\"array\"><value><a>1</a></value><value><b type=\"integer\">2</b></value><value><c>/.*/</c></value></values></foo><bar>baz</bar></hash>"
137
- tree = Nokogiri::XML(xml_tree)
138
- @em.send(:matcher_pathes_from, tree).should be_a(Array)
139
- @em.send(:matcher_pathes_from, tree).include?("/hash/bla").should be_true
140
- @em.send(:matcher_pathes_from, tree).include?("/hash/foo/values/*/a").should be_true
141
- @em.send(:matcher_pathes_from, tree).include?("/hash/foo/values/*/b").should be_true
142
- @em.send(:matcher_pathes_from, tree).include?("/hash/foo/values/*/c").should be_true
143
- @em.send(:matcher_pathes_from, tree).include?("/hash/bar").should be_true
144
- @em.send(:matcher_pathes_from, tree).each do |path|
145
- path.should be_a(String)
146
- end
147
- end
148
- end
149
-
150
- describe 'relative_path' do
151
- it 'should substitute an absolute addressing in a given path' do
152
- path = "/bla/foo/values[6]/duffy/duck"
153
- @em.send(:relative_path, path).should eql "/bla/foo/*/duffy/duck"
154
- end
155
- it 'should substitute more than one absolute adressing in a given path' do
156
- path = "/bla/foo/values[6]/duffy/friends[1]/duck"
157
- @em.send(:relative_path, path).should eql "/bla/foo/*/duffy/*/duck"
158
- end
159
- it 'should return a string' do
160
- path = "/bla/foo/values[6]/duffy/friends[1]/duck"
161
- @em.send(:relative_path, path).should be_a(String)
162
- end
163
- end
164
-
165
- describe 'excluded?' do
166
- before(:each) do
167
- @em = ExpectationMatcher.new(['foo', 'bar'])
168
- end
169
- it 'should return true if the given string is present in the @excludes instance variable of the class' do
170
- @em.send(:excluded?, 'foo').should be_true
171
- end
172
- it 'should return false if the given string is not present in the @excludes instance variable of the class' do
173
- @em.send(:excluded?, 'fooz').should be_false
174
- end
175
- end
176
-
177
- describe 'is_regex?' do
178
- it 'should return true if the given string seems to be a regular expression' do
179
- string = "/^\d{3}$/"
180
- @em.send(:is_regex?, string).should be_true
181
- end
182
- it 'should return false if the given string does not seem to be a regular expression' do
183
- string = "fooz"
184
- @em.send(:is_regex?, string).should be_false
185
- string = "/fooz"
186
- @em.send(:is_regex?, string).should be_false
187
- string = "fooz/"
188
- @em.send(:is_regex?, string).should be_false
189
- end
190
- end
191
-
192
- describe 'regex_matches?' do
193
- it 'should return true if the given regular expression matches the given value' do
194
- regex = "^\\d{2}$"
195
- value = "12"
196
- @em.send(:regex_matches?, regex, value).should be_true
197
- end
198
- it 'should return false if the giveb reular expression does not match the given value' do
199
- regex = "^\\d{2}$"
200
- value = "123"
201
- @em.send(:regex_matches?, regex, value).should be_false
202
- value = "foo"
203
- @em.send(:regex_matches?, regex, value).should be_false
204
- end
205
- end
206
-
207
- describe 'string_matches?' do
208
- it 'should return true if the given string matches the given value' do
209
- string = "bar"
210
- value = "bar"
211
- @em.send(:string_matches?, string, value).should be_true
212
- end
213
- it 'should return false if the given string does not match the given value' do
214
- string = "bar"
215
- value = "foo"
216
- @em.send(:string_matches?, string, value).should be_false
217
- end
218
- end
219
-
220
- describe 'valid_json?' do
221
- it 'should return true if the given response body consists of valid JSON' do
222
- validateable = { :foo => "bar" }.to_json
223
- @em.send(:valid_json?, validateable).should be_true
224
- end
225
- it 'should return true if the given response body is nil' do
226
- @em.send(:valid_json?, nil).should be_true
227
- end
228
- it 'should return false if the given response body consists of anything else but valid JSON' do
229
- @em.send(:valid_json?, "foobar").should be_false
4
+ describe "initialize" do
5
+ it "should have a properly filled instance variable @excludes after instanciation" do
6
+ @e = ExpectationMatcher.new(["exclude1","exclude2","exclude3"])
7
+ @e.instance_variable_get(:@excludes).should be_a(Array)
8
+ @e.instance_variable_get(:@excludes).size.should == 3
9
+ @e.instance_variable_get(:@excludes)[0].should eql "exclude1"
10
+ end
11
+ it "should habe an empty array in @excludes if no excludes were given" do
12
+ @e = ExpectationMatcher.new()
13
+ @e.instance_variable_get(:@excludes).should be_a(Array)
14
+ @e.instance_variable_get(:@excludes).size.should == 0
15
+ end
16
+ end
17
+ describe "check" do
18
+ it "should invoke check at the given plugin" do
19
+ @e = ExpectationMatcher.new
20
+ @e.should_receive(:test_plugin).once.with({ :response => "1" }, { :testcase => "2" })
21
+ @e.check("TestPlugin", { :response => "1"}, { :testcase => "2" })
22
+ end
23
+ end
24
+ describe "self.initialize_plugins" do
25
+ it "should create private invocation methods for every plugin" do
26
+ pending "TODO"
27
+ ExpectationMatcher.should_receive(:available_plugins).and_return(["PluginNoOne", "PluginNoTwo", "PluginNoThree"])
28
+ @e = ExpectationMatcher.new
29
+ # FIXME private methods
30
+ @e.should respond_to(:plugin_no_one)
31
+ @e.should respond_to(:plugin_no_two)
32
+ @e.should respond_to(:plugin_no_three)
230
33
  end
231
34
  end
232
35
  end
@@ -2,46 +2,73 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe 'http_client' do
4
4
  before(:each) do
5
- @http_client = HttpClient.new
5
+ @http_client = HttpClient.new("http", "localhost", 3000, "namespace")
6
6
  any_response = Struct.new(:code, :message, :headers, :body)
7
7
  @response = any_response.new(:code => 200, :message => "Ok", :headers => {:foo => ["baz" => "bar"], :body => {:a => "b"}})
8
8
  end
9
9
  describe 'send_request' do
10
- it 'should invoke a send request in the underlying http class with the given method, uri and data' do
11
- @http_client.class.should_receive(:put)
12
- @http_client.should_receive(:build_response).and_return(@response)
13
- @http_client.send_request(:put, "http://foo.bar", nil)
14
-
15
- @http_client.class.should_receive(:get)
16
- @http_client.should_receive(:build_response).and_return(@response)
17
- @http_client.send_request(:get, "http://foo.bar", nil)
10
+ it 'should invoke a PUT request in the underlying http class with the given method, uri and data' do
11
+ @http_client.stub(:build_response).and_return(@response)
12
+ @http_client.should_receive(:put).and_return(@response)
13
+ @http_client.send_request(:put, "/path/to/resource", nil, { :data => "2" }, { :params => "3" })
14
+ end
15
+ it 'should invoke a GET request in the underlying http class with the given method, uri and data' do
16
+ @http_client.stub(:build_response).and_return(@response)
17
+ @http_client.should_receive(:get).and_return(@response)
18
+ @http_client.send_request(:get, "/path/to/resource", nil, { :data => "2" }, { :params => "3" })
18
19
  end
19
- it 'should invoke build response and return its output to the caller' do
20
- @http_client.should_receive(:build_response).and_return("response")
21
- @http_client.send_request(:put, "http://foo.bar", nil).should eql "response"
20
+ it 'should invoke a POST request in the underlying http class with the given method, uri and data' do
21
+ @http_client.stub(:build_response).and_return(@response)
22
+ @http_client.should_receive(:post).and_return(@response)
23
+ @http_client.send_request(:post, "/path/to/resource", nil, { :data => "2" }, { :params => "3" })
22
24
  end
23
- it 'should not fatal if expected data attribute is nil' do
24
- pending "TODO: pair this one"
25
- @http_client.should_receive(:build_response).and_return(@response)
26
- @http_client.send_request(:put, "http://foo.bar", nil).should_not raise_error
25
+ it 'should invoke a DELETE request in the underlying http class with the given method, uri and data' do
26
+ @http_client.stub(:build_response).and_return(@response)
27
+ @http_client.should_receive(:delete).and_return(@response)
28
+ @http_client.send_request(:delete, "/path/to/resource", nil, { :data => "2" }, { :params => "3" })
27
29
  end
28
30
  end
29
-
30
31
  describe 'build_response' do
31
32
  it 'should return a struct consisting of 4 symbols: :code, :message, :headers and :body with right types' do
32
33
  raw_response_struct = Struct.new(:code, :message, :headers, :body)
33
34
  response = raw_response_struct.new
34
-
35
35
  response.code = 404
36
36
  response.message = "Hi Duffy Duck"
37
- response.headers = { :foo => ["bar" => "baz"] }
37
+ response.headers = { :daisy => "duck" }
38
38
  response.body = { :duffy => "duck" }
39
-
40
- @http_client.send(:build_response, response).to_s.should eql response.to_s
41
39
  @http_client.send(:build_response, response).code.should_not be_nil
42
40
  @http_client.send(:build_response, response).message.should_not be_nil
43
- @http_client.send(:build_response, response).body.should_not be_nil
44
- @http_client.send(:build_response, response).headers.should_not be_nil
41
+ @http_client.send(:build_response, response).body.should == {:duffy => "duck"}
42
+ @http_client.send(:build_response, response).headers.should == {"daisy" => "duck"}
43
+ end
44
+ end
45
+ describe "resource_path" do
46
+ it "should return a resource path extended by the namespace if one is set" do
47
+ @http_client.send(:resource_path, "/users/duffyduck").match(@http_client.instance_variable_get(:@namespace)).should_not be_nil
48
+ end
49
+ it "should return a correct resource path even if no namespace is set" do
50
+ @http_client.instance_variable_set(:@namespace, nil)
51
+ @http_client.send(:resource_path, "/users/duffyduck").match(/\/users\/duffyduck/).should_not be_nil
52
+ end
53
+ end
54
+ describe "build_uri" do
55
+ it "should return a correct uri from the given parameters" do
56
+ @http_client.send(:build_uri,"/users/duffyduck").should_not be_nil
57
+ @http_client.send(:build_uri,"/users/duffyduck").to_s.match(@http_client.instance_variable_get(:@protocol)).should_not be_nil
58
+ @http_client.send(:build_uri,"/users/duffyduck").to_s.match(@http_client.instance_variable_get(:@host)).should_not be_nil
59
+ @http_client.send(:build_uri,"/users/duffyduck").to_s.match(@http_client.instance_variable_get(:@port).to_s).should_not be_nil
60
+ @http_client.send(:build_uri,"/users/duffyduck").to_s.match(@http_client.instance_variable_get(:@namespace)).should_not be_nil
61
+ end
62
+ it "should only include a port in uri if a port was specified or port was set to 80" do
63
+ @http_client.instance_variable_set(:@port, nil)
64
+ @http_client.send(:build_uri,"/users/duffyduck").to_s.match("80").should be_nil
65
+ @http_client.instance_variable_set(:@port, 80)
66
+ @http_client.send(:build_uri,"/users/duffyduck").to_s.match("80").should be_nil
67
+ end
68
+ it "should add given GET parameters in correct notation" do
69
+ @http_client.send(:build_uri,"/users/duffyduck", {:param1 => "1", :param2 => "a"}).to_s.match(/\?param/).should_not be_nil
70
+ @http_client.send(:build_uri,"/users/duffyduck", {:param1 => "1", :param2 => "a"}).to_s.match(/param1=1/).should_not be_nil
71
+ @http_client.send(:build_uri,"/users/duffyduck", {:param1 => "1", :param2 => "a"}).to_s.match(/param2=a/).should_not be_nil
45
72
  end
46
73
  end
47
74
  end
@@ -0,0 +1,45 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "result" do
4
+ before(:all) do
5
+ @r = Result.new({ :name => "testcase_name" }, {})
6
+ end
7
+ describe "verbose_on_error" do
8
+ it "should invoke be_verbose if an error occured" do
9
+ @r.instance_variable_set(:@succeeded, false)
10
+ @r.should_receive(:be_verbose).once
11
+ @r.send(:verbose_on_error, 1)
12
+ end
13
+ it "should not invoke be_verbose if no error occured" do
14
+ @r.instance_variable_set(:@succeeded, true)
15
+ @r.should_receive(:be_verbose).exactly(0).times
16
+ @r.send(:verbose_on_error, 1)
17
+ end
18
+ end
19
+ describe "verbose_on_success" do
20
+ it "should invoke be_verbose in case of an error" do
21
+ @r.instance_variable_set(:@succeeded, false)
22
+ @r.should_receive(:be_verbose).once
23
+ @r.send(:verbose_on_success, 1)
24
+ end
25
+ it "should invoke be_verbose in case of no error too" do
26
+ @r.instance_variable_set(:@succeeded, true)
27
+ @r.should_receive(:be_verbose).once
28
+ @r.send(:verbose_on_success, 1)
29
+ end
30
+ end
31
+ describe "verbose_with_curl" do
32
+ it "should invoke be_verbose in case of an error" do
33
+ @r.instance_variable_set(:@succeeded, false)
34
+ @r.should_receive(:be_verbose).once
35
+ @r.send(:verbose_with_curl, 1)
36
+ end
37
+ it "should invoke be_verbose in case of no error too" do
38
+ @r.instance_variable_set(:@succeeded, true)
39
+ @r.should_receive(:be_verbose).once
40
+ @r.send(:verbose_with_curl, 1)
41
+ end
42
+ end
43
+ end
44
+
45
+
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 5
9
- version: 0.3.5
8
+ - 6
9
+ version: 0.3.6
10
10
  platform: ruby
11
11
  authors:
12
12
  - jan@moviepilot.com
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-07 00:00:00 +02:00
17
+ date: 2010-10-12 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -234,7 +234,6 @@ files:
234
234
  - lib/apirunner.rb
235
235
  - lib/apirunner/railtie.rb
236
236
  - lib/checker.rb
237
- - lib/core_extensions.rb
238
237
  - lib/expectation_matcher.rb
239
238
  - lib/http_client.rb
240
239
  - lib/plugins/plug01_response_json_syntax_checker.rb
@@ -242,12 +241,16 @@ files:
242
241
  - lib/plugins/plug03_response_header_checker.rb
243
242
  - lib/plugins/plug04_response_body_checker.rb
244
243
  - lib/result.rb
244
+ - lib/string_ext.rb
245
245
  - lib/tasks/api.rake
246
246
  - lib/testcase.rb
247
247
  - spec/.rspec
248
+ - spec/api_configuration_spec.rb
248
249
  - spec/api_runner_spec.rb
250
+ - spec/checker_spec.rb
249
251
  - spec/expectation_matcher_spec.rb
250
252
  - spec/http_client_spec.rb
253
+ - spec/result_spec.rb
251
254
  - spec/spec_helper.rb
252
255
  has_rdoc: true
253
256
  homepage: http://github.com/moviepilot/apirunner
@@ -263,7 +266,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
263
266
  requirements:
264
267
  - - ">="
265
268
  - !ruby/object:Gem::Version
266
- hash: 4004679743371264897
269
+ hash: 2715016286846955498
267
270
  segments:
268
271
  - 0
269
272
  version: "0"
@@ -283,7 +286,10 @@ signing_key:
283
286
  specification_version: 3
284
287
  summary: one-line summary of your gem
285
288
  test_files:
289
+ - spec/api_configuration_spec.rb
286
290
  - spec/api_runner_spec.rb
291
+ - spec/checker_spec.rb
287
292
  - spec/expectation_matcher_spec.rb
288
293
  - spec/http_client_spec.rb
294
+ - spec/result_spec.rb
289
295
  - spec/spec_helper.rb
@@ -1,17 +0,0 @@
1
- module CoreExtensions
2
- class String
3
- # generates filenames from classnames the rails way
4
- def underscore(string)
5
- string.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
6
- end
7
-
8
- # opposites underscore defined above
9
- def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
10
- if first_letter_in_uppercase
11
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
12
- else
13
- lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
14
- end
15
- end
16
- end
17
- end