apirunner 0.3.5 → 0.3.6

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