ananke 0.0.1

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/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "sinatra", "~>1.1.2"
4
+
5
+ group :development, :test do
6
+ gem "colored", "~>1.2"
7
+ gem "json", "~>1.5.1"
8
+ gem "rack-test", "~>0.5.6"
9
+ gem "rake", "~>0.8.7"
10
+ gem "rspec", "~>2.5.0"
11
+ gem 'simplecov', '~>0.3.9'
12
+ end
13
+
14
+
15
+
data/README.rdoc ADDED
@@ -0,0 +1,114 @@
1
+ = Ananke
2
+
3
+ Ananke is a DSL that extends the functionality of Sinatra for easy creation of Restful Services and Resources:
4
+
5
+ #myapp.rb
6
+ require 'ananke'
7
+ require 'sinatra/main' #This is only for Demo purposes
8
+ #--------------------Repositories---------------------
9
+ module Repository
10
+ module User
11
+ @data = [{:id => '1', :name => 'One'}, {:id => '2', :name => 'Two'}]
12
+ def self.all
13
+ @data.to_s
14
+ end
15
+ def self.one(id)
16
+ index = @data.index{ |d| d[:id] == id}
17
+ (index.nil? && '') || @data[index].to_s
18
+ end
19
+ end
20
+ end
21
+ #-------------------REST Resources--------------------
22
+ rest :user do
23
+ id :id
24
+ end
25
+
26
+ Install the gem and run with:
27
+
28
+ gem install ananke
29
+ ruby -rubygems myapp.rb
30
+
31
+ All Users
32
+ http://localhost:4567/user
33
+ One User
34
+ http://localhost:4567/user/1
35
+
36
+ == REST Resources
37
+ `rest` defines a complete Resource, and constructs Sinatra Routes
38
+ based on what's available in it's respective Repository. Routes are:
39
+
40
+ get '/name/?' -> Repository::Capitalize(name).all
41
+ get '/name/id' -> Repository::Capitalize(name).one(id)
42
+ post '/name' -> Repository::Capitalize(name).new(data)
43
+ put '/name/id' -> Repository::Capitalize(name).edit(id, data)
44
+ delete '/name/id' -> Repository::Capitalize(name).delete(id)
45
+
46
+ The REST media type can be built up:
47
+
48
+ required :name
49
+ optional :country
50
+
51
+ == Repositories
52
+ The Default Repository can be changed:
53
+
54
+ ananke.default_repository = 'MyRepository'
55
+
56
+ == Validation
57
+ Validation can be added on any field by providing arguments after a field declaration:
58
+
59
+ required :name, :length => 4
60
+
61
+ This will cause the paramater to be validated against the method defined in Ananke::Rules. Custom Rules
62
+ can be added to the module and provided as arguments. Current Default included rules are:
63
+
64
+ length(min)
65
+
66
+ Validation Methods are Invoked in the Ananke::Rules context, and has access to a class variable named
67
+ value, which holds the value for the currently valuated Parameter.
68
+
69
+ To Add a Custom Rule:
70
+
71
+ rule :name, do
72
+ value == [expected] ? nil : 'Not Expected Value'
73
+ end
74
+
75
+ required :name, :name
76
+
77
+ or
78
+
79
+ module Ananke
80
+ module Rules
81
+ def validate_name
82
+ value == [expected] ? nil : 'Not Expected Value'
83
+ end
84
+ end
85
+ end
86
+
87
+ required :name, :name
88
+
89
+ or Advanced
90
+
91
+ module Ananke
92
+ module Rules
93
+ def validate_name(extra)
94
+ value == [expected using extra] ? nil : 'Not Expected Value'
95
+ end
96
+ end
97
+ end
98
+
99
+ required :name, :name => extra
100
+
101
+ == Future
102
+ A short list of future development:
103
+ - Refactor!
104
+ - Return Value Strategy
105
+ - Resource Exposes Media Type
106
+ - HyperMedia
107
+ - Lots more `bullet-proofing`
108
+ - ETag Support
109
+
110
+ == More
111
+
112
+ * {Project Website}[http://https://github.com/HasAndries/ananke/]
113
+ * {Issue tracker}[https://github.com/HasAndries/ananke/issues]
114
+ * {Twitter}[http://twitter.com/HasAndries]
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require "rake"
3
+ require "rake/rdoctask"
4
+ require 'rake/gempackagetask'
5
+ require "rspec/core/rake_task"
6
+
7
+ require File.expand_path("../lib/version", __FILE__)
8
+ gemspec = Gem::Specification.new do |gem|
9
+ gem.name = "ananke"
10
+ gem.version = Ananke::VERSION
11
+ gem.platform = Gem::Platform::RUBY
12
+ gem.authors = ["Andries Coetzee"]
13
+ gem.email = "andriesc@mixtel.com"
14
+ gem.summary = "#{gem.name}-#{Ananke::VERSION}"
15
+ gem.description = "Full REST Implementation on top of Sinatra"
16
+ gem.homepage = "https://github.com/HasAndries/ananke"
17
+
18
+ gem.rubygems_version = "1.5.0"
19
+
20
+ gem.files = FileList['lib/**/*', 'spec/**/*', 'Gemfile', 'Rakefile', 'README.rdoc']
21
+ gem.test_files = FileList['spec/**/*']
22
+ gem.extra_rdoc_files = [ "README.rdoc" ]
23
+ gem.rdoc_options = ["--charset=UTF-8"]
24
+ gem.require_path = "lib"
25
+
26
+ gem.post_install_message = %Q{**************************************************
27
+
28
+ Thank you for installing #{gem.summary}
29
+
30
+ Please be sure to look at README.rdoc to see what might have changed
31
+ since the last release and how to use this GEM.
32
+
33
+ **************************************************
34
+ }
35
+ gem.add_dependency "sinatra", "~> 1.1.2"
36
+
37
+ gem.add_development_dependency "colored", "~> 1.2"
38
+ gem.add_development_dependency "json", "~> 1.5.1"
39
+ gem.add_development_dependency "rack-test", "~> 0.5.6"
40
+ gem.add_development_dependency "rake", "~> 0.8.7"
41
+ gem.add_development_dependency "rspec", "~> 2.5.0"
42
+ gem.add_development_dependency "simplecov", "~> 0.3.9"
43
+ end
44
+
45
+ Rake::GemPackageTask.new(gemspec) do |pkg|
46
+ pkg.need_tar = true
47
+ end
48
+
49
+ desc %{Build the gemspec file.}
50
+ task :gemspec do
51
+ gemspec.validate
52
+ File.open("#{gemspec.name}.gemspec", 'w'){|f| f.write gemspec.to_ruby }
53
+ end
54
+
55
+ RSpec::Core::RakeTask.new(:test) do |t|
56
+ t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
57
+ t.pattern = 'spec/**/*_spec.rb'
58
+ end
59
+
60
+ RSpec::Core::RakeTask.new(:doc) do |t|
61
+ t.rspec_opts = ["-c" "-r ./spec/nice_formatter.rb", "-f NiceFormatter", "-o doc.htm"]
62
+ t.pattern = 'spec/**/*_spec.rb'
63
+ end
64
+
65
+ task :default => [:test]
data/lib/ananke.rb ADDED
@@ -0,0 +1,109 @@
1
+ require 'sinatra/base'
2
+
3
+ module Ananke
4
+ class << self
5
+ attr_accessor :default_repository, :rules
6
+ end
7
+
8
+ private
9
+ @default_repository = 'Repository'
10
+ @rules = [:length]
11
+
12
+ def build(path)
13
+ #TODO - Check if Modules Exist
14
+ mod = Module.const_get(Ananke.default_repository.to_sym).const_get("#{path.capitalize}".to_sym)
15
+ key = @id[:key]
16
+ fields = @fields
17
+ links = @links
18
+
19
+ #TODO - Check if Repository Supports Resource
20
+ Sinatra::Base.get "/#{path}/:#{key}" do
21
+ ret = mod.one(params[key]) if !params[key].nil?
22
+ #TODO - Hyper Links(Common place maybe?)
23
+ ret.respond_to?(:to_json) ? ret.to_json : ret
24
+ end
25
+
26
+ #TODO - Check if Repository Supports Resource
27
+ Sinatra::Base.get "/#{path}/?" do
28
+ ret = mod.all
29
+ #TODO - Hyper Links(Common place maybe?)
30
+ ret.respond_to?(:to_json) ? ret.to_json : ret
31
+ end
32
+
33
+ #TODO - Check if Repository Supports Resource
34
+ Sinatra::Base.post "/#{path}/?" do
35
+ #TODO - Parameter Validation
36
+ status, message = validate!(fields, params)
37
+ error status, message unless status.nil?
38
+ ret = mod.new(params)
39
+ status 201
40
+ #TODO - Hyper Links for Created Resource
41
+ end
42
+
43
+ #TODO - Check if Repository Supports Resource
44
+ Sinatra::Base.put "/#{path}/:#{key}" do
45
+ #TODO - Parameter Validation
46
+ mod.edit(params[key], params) if !params[key].nil?
47
+ status 200
48
+ #TODO - Hyper Links
49
+ end
50
+
51
+ #TODO - Check if Repository Supports Resource
52
+ Sinatra::Base.delete "/#{path}/:#{key}" do
53
+ #TODO - Parameter Validation
54
+ mod.delete(params[key]) if !params[key].nil?
55
+ status 200
56
+ end
57
+ end
58
+
59
+ def validate!(fields, params)
60
+ errors = []
61
+ fields.each do |field|
62
+ value = params[field[:key].to_s]
63
+ errors << "Missing Required Parameter: #{field[:key]}" if field[:type] == :required && value.nil?
64
+ Ananke::Rules.value = value
65
+ field[:rules].each do |r|
66
+ res = r.class == Hash ? Ananke::Rules.send("validate_#{r.first[0]}", r.first[1]) : Ananke::Rules.send("validate_#{r}")
67
+ errors << "#{field[:key]}: #{res}" unless res.nil?
68
+ end
69
+ end
70
+ return 400, errors unless errors.empty?
71
+ end
72
+
73
+ public
74
+
75
+ def rest(path, &block)
76
+ @id = {}
77
+ @fields = []
78
+ @links = []
79
+ yield block
80
+ build path
81
+ end
82
+
83
+ def id(key, *rules)
84
+ @id = {:key => key, :type => :id, :rules => rules}
85
+ end
86
+ def required(key, *rules)
87
+ @fields << {:key => key, :type => :required, :rules => rules}
88
+ end
89
+ def optional(key, *rules)
90
+ @fields << {:key => key, :type => :optional, :rules => rules}
91
+ end
92
+ def media(rel, method, resource, field)
93
+ @links << {:rel => rel, :method => method, :resource => resource, :field => field}
94
+ end
95
+ def rule(name, &block)
96
+ Ananke::Rules.send(:define_singleton_method, "validate_#{name}", block)
97
+ end
98
+
99
+ module Rules
100
+ class << self
101
+ attr_accessor :value
102
+ end
103
+ def self.validate_length(min)
104
+ value.length >= min ? nil : "Value must be at least #{min} characters long"
105
+ end
106
+ end
107
+ end
108
+
109
+ include Ananke
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Ananke
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.adapters.define 'cov' do
4
+ coverage_dir 'public/coverage'
5
+
6
+ add_filter '/dump/'
7
+ add_filter '/public/'
8
+ add_filter '/spec/'
9
+ end
@@ -0,0 +1,126 @@
1
+ require './spec/spec_helper'
2
+ require './lib/ananke'
3
+
4
+ describe 'Resource' do
5
+ include Rack::Test::Methods
6
+ include Ananke
7
+
8
+ def app
9
+ Sinatra::Base
10
+ end
11
+
12
+ before(:all) do
13
+ rest :user do
14
+ id :user_id
15
+ required :username
16
+ required 'email'
17
+ optional :country
18
+
19
+ media "Get All Vehicles", :get, :vehicles, :user_id
20
+ end
21
+ end
22
+
23
+ it """
24
+ Should setup the defaults for ReST
25
+ """ do
26
+ Ananke.default_repository.should == 'Repository'
27
+ end
28
+
29
+ it """
30
+ Should setup Routes
31
+ """ do
32
+ Sinatra::Base.routes["GET"][-1][0].inspect.include?('user').should == true
33
+ Sinatra::Base.routes["GET"].length.should == 2
34
+ Sinatra::Base.routes["POST"][-1][0].inspect.include?('user').should == true
35
+ Sinatra::Base.routes["PUT"][-1][0].inspect.include?('user').should == true
36
+ Sinatra::Base.routes["DELETE"][-1][0].inspect.include?('user').should == true
37
+ end
38
+
39
+ #----------------------------BASIC--------------------------------------
40
+ it """
41
+ GET /user
42
+ - code: 200
43
+ - content-type: text/plain
44
+ - body: [{:id=>1, :name=>'one'}, {:id => 2, :name => 'two'}]
45
+ """ do
46
+ get "/user"
47
+ last_response.status.should == 200
48
+ last_response.body.should == Repository::User.data.to_json
49
+ end
50
+
51
+ it """
52
+ GET /user/1
53
+ - code: 200
54
+ - content-type: text/plain
55
+ - body: {user_id: ,username: ,email: ,country: }
56
+ """ do
57
+ get "/user/1"
58
+ last_response.status.should == 200
59
+ last_response.body.should == Repository::User.data[0].to_json
60
+ end
61
+
62
+ it """
63
+ POST /user
64
+ - body: {user_id: ,username: ,email: ,country: }
65
+ RETURN
66
+ - code: 201
67
+ - content-type: text/json
68
+ - body:
69
+ """ do
70
+ post "/user", body={:user_id => 3, :username => 'three', :email => '3@three.com', :country => 'USA'}
71
+ last_response.status.should == 201
72
+ last_response.body.should == ''
73
+ end
74
+
75
+ it """
76
+ PUT /user/3
77
+ - body: {user_id: ,username: ,email: ,country: }
78
+ RETURN
79
+ - code: 200
80
+ - content-type: text/json
81
+ - body:
82
+ """ do
83
+ put "/user/3", body={:user_id => 3, :username => 'four', :email => '4@four.com', :country => 'Russia'}
84
+ last_response.status.should == 200
85
+ last_response.body.should == ''
86
+ end
87
+
88
+ it """
89
+ DELETE /user/3
90
+ RETURN
91
+ - code: 200
92
+ - content-type: text/json
93
+ - body:
94
+ """ do
95
+ delete "/user/3"
96
+ last_response.status.should == 200
97
+ last_response.body.should == ''
98
+ end
99
+ end
100
+
101
+ module Repository
102
+ module User
103
+ @data = [{:user_id => 1, :username => 'one', :email => '1@one.com', :country => 'South Africa'},
104
+ {:user_id => 2, :username => 'two', :email => '2@two.com', :country => 'England'}]
105
+
106
+ def self.data
107
+ @data
108
+ end
109
+
110
+ def self.one(id)
111
+ @data[@data.index{ |d| d[:user_id] == id.to_i}]
112
+ end
113
+ def self.all
114
+ @data
115
+ end
116
+ def self.new(data)
117
+ @data << data
118
+ end
119
+ def self.edit(id, data)
120
+ @data.each { |d| d = data if d[:user_id] == id}
121
+ end
122
+ def self.delete(id)
123
+ @data.delete_if { |i| i[:user_id] == id}
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,89 @@
1
+ require './spec/spec_helper'
2
+ require './lib/ananke'
3
+
4
+ describe 'Resource' do
5
+ include Rack::Test::Methods
6
+ include Ananke
7
+
8
+ def app
9
+ Sinatra::Base
10
+ end
11
+
12
+ #--------------------------VALIDATION-----------------------------------
13
+ it """
14
+ Should be able to use Predefined Validation:
15
+ length
16
+ """ do
17
+ module Repository
18
+ module Basic
19
+ def self.new(data)end
20
+ end
21
+ end
22
+ rest :basic do
23
+ id :user_id
24
+ required :username, :length => 4
25
+ end
26
+
27
+ post "/basic", body={:user_id => 1, :username => ''}
28
+ last_response.status.should == 400
29
+ last_response.body.should == 'username: Value must be at least 4 characters long'
30
+
31
+ post "/basic", body={:user_id => 1, :username => '1234'}
32
+ last_response.status.should == 201
33
+ end
34
+
35
+ it """
36
+ Should be able to use Explicitly Defined Rule
37
+ """ do
38
+ module Ananke
39
+ module Rules
40
+ def self.validate_email
41
+ value =~ /[\w._%-]+@[\w.-]+.[a-zA-Z]{2,4}/ ? nil : "Invalid Email: #{value}"
42
+ end
43
+ end
44
+ end
45
+ Ananke::Rules.respond_to?('validate_email').should == true
46
+
47
+ module Repository
48
+ module Explicit
49
+ def self.new(data)end
50
+ end
51
+ end
52
+ rest :explicit do
53
+ id :user_id
54
+ required :email, :email
55
+ end
56
+
57
+ post "/explicit", body={:user_id => 1, :email => 'some'}
58
+ last_response.status.should == 400
59
+ last_response.body.should == 'email: Invalid Email: some'
60
+
61
+ post "/explicit", body={:user_id => 1, :email => 'some1@some.com'}
62
+ last_response.status.should == 201
63
+ end
64
+
65
+ it """
66
+ Should be able to Add new Validations and Use them
67
+ """ do
68
+ rule :country, do
69
+ value == 'South Africa' ? nil : 'Not from South Africa'
70
+ end
71
+ module Repository
72
+ module Added
73
+ def self.new(data)end
74
+ end
75
+ end
76
+ rest :added do
77
+ id :user_id
78
+ required :country, :country
79
+ end
80
+ Ananke::Rules.respond_to?('validate_country').should == true
81
+
82
+ post "/added", body={:user_id => 1, :country => 'England'}
83
+ last_response.status.should == 400
84
+ last_response.body.should == 'country: Not from South Africa'
85
+
86
+ post "/added", body={:user_id => 1, :country => 'South Africa'}
87
+ last_response.status.should == 201
88
+ end
89
+ end
@@ -0,0 +1,346 @@
1
+ require 'erb'
2
+ require 'rspec/core/formatters/base_text_formatter'
3
+ require 'rspec/core/formatters/snippet_extractor'
4
+
5
+ class NiceFormatter < RSpec::Core::Formatters::BaseTextFormatter
6
+ include ERB::Util # for the #h method
7
+
8
+ def method_missing(m, *a, &b)
9
+ # no-op
10
+ end
11
+
12
+ def message(message)
13
+ end
14
+
15
+ def initialize(output)
16
+ super(output)
17
+ @example_group_number = 0
18
+ @example_number = 0
19
+ @header_red = nil
20
+ end
21
+
22
+ # The number of the currently running example_group
23
+ def example_group_number
24
+ @example_group_number
25
+ end
26
+
27
+ # The number of the currently running example (a global counter)
28
+ def example_number
29
+ @example_number
30
+ end
31
+
32
+ def start(example_count)
33
+ super(example_count)
34
+ @output.puts html_header
35
+ @output.puts report_header
36
+ @output.flush
37
+ end
38
+
39
+ def example_group_started(example_group)
40
+ super(example_group)
41
+ @example_group_red = false
42
+ @example_group_number += 1
43
+ unless example_group_number == 1
44
+ @output.puts " </dl>"
45
+ @output.puts "</div>"
46
+ end
47
+ @output.puts "<div class=\"example_group\">"
48
+ @output.puts " <dl>"
49
+ @output.puts " <dt id=\"example_group_#{example_group_number}\">#{example_group.description.gsub(/[\n]/, "<br />")}</dt>"
50
+ @output.flush
51
+ end
52
+
53
+ def start_dump
54
+ @output.puts " </dl>"
55
+ @output.puts "</div>"
56
+ @output.flush
57
+ end
58
+
59
+ def example_started(example)
60
+ super(example)
61
+ @example_number += 1
62
+ end
63
+
64
+ def example_passed(example)
65
+ move_progress
66
+ @output.puts " <dd class=\"spec passed\"><span class=\"passed_spec_name\">#{example.description.gsub(/[\n]/, "<br />")}</span></dd>"
67
+ @output.flush
68
+ end
69
+
70
+ def example_failed(example)
71
+ counter = 0
72
+ exception = example.metadata[:execution_result][:exception_encountered]
73
+ extra = extra_failure_content(exception)
74
+ failure_style = 'failed'
75
+ failure_style = RSpec::Core::PendingExampleFixedError === exception ? 'pending_fixed' : 'failed'
76
+ @output.puts " <script type=\"text/javascript\">makeRed('rspec-header');</script>" unless @header_red
77
+ @header_red = true
78
+ @output.puts " <script type=\"text/javascript\">makeRed('example_group_#{example_group_number}');</script>" unless @example_group_red
79
+ @example_group_red = true
80
+ move_progress
81
+ @output.puts " <dd class=\"spec #{failure_style}\">"
82
+ @output.puts " <span class=\"failed_spec_name\">#{h(example.description.gsub(/[\n]/, "<br />"))}</span>"
83
+ @output.puts " <div class=\"failure\" id=\"failure_#{counter}\">"
84
+ @output.puts " <div class=\"message\"><pre>#{h(exception.message)}</pre></div>" unless exception.nil?
85
+ @output.puts " <div class=\"backtrace\"><pre>#{format_backtrace(exception.backtrace, example).join("\n")}</pre></div>" if exception
86
+ @output.puts extra unless extra == ""
87
+ @output.puts " </div>"
88
+ @output.puts " </dd>"
89
+ @output.flush
90
+ end
91
+
92
+ def example_pending(example)
93
+ message = example.metadata[:execution_result][:pending_message]
94
+ @output.puts " <script type=\"text/javascript\">makeYellow('rspec-header');</script>" unless @header_red
95
+ @output.puts " <script type=\"text/javascript\">makeYellow('example_group_#{example_group_number}');</script>" unless @example_group_red
96
+ move_progress
97
+ @output.puts " <dd class=\"spec not_implemented\"><span class=\"not_implemented_spec_name\">#{example.description.gsub(/[\n]/, "<br />")} (PENDING: #{h(message)})</span></dd>"
98
+ @output.flush
99
+ end
100
+
101
+ # Override this method if you wish to output extra HTML for a failed spec. For example, you
102
+ # could output links to images or other files produced during the specs.
103
+ #
104
+ def extra_failure_content(exception)
105
+ require 'rspec/core/formatters/snippet_extractor'
106
+ @snippet_extractor ||= RSpec::Core::Formatters::SnippetExtractor.new
107
+ " <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(exception)}</code></pre>"
108
+ end
109
+
110
+ def move_progress
111
+ @output.puts " <script type=\"text/javascript\">moveProgressBar('#{percent_done}');</script>"
112
+ @output.flush
113
+ end
114
+
115
+ def percent_done
116
+ result = 100.0
117
+ if @example_count > 0
118
+ result = ((example_number).to_f / @example_count.to_f * 1000).to_i / 10.0
119
+ end
120
+ result
121
+ end
122
+
123
+ def dump_failures
124
+ end
125
+
126
+ def dump_pending
127
+ end
128
+
129
+ def dump_summary(duration, example_count, failure_count, pending_count)
130
+ # TODO - kill dry_run?
131
+ if dry_run?
132
+ totals = "This was a dry-run"
133
+ else
134
+ totals = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
135
+ totals << ", #{pending_count} pending" if pending_count > 0
136
+ end
137
+ @output.puts "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{duration} seconds</strong>\";</script>"
138
+ @output.puts "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
139
+ @output.puts "</div>"
140
+ @output.puts "</div>"
141
+ @output.puts "</body>"
142
+ @output.puts "</html>"
143
+ @output.flush
144
+ end
145
+
146
+ def html_header
147
+ <<-EOF
148
+ <?xml version="1.0" encoding="UTF-8"?>
149
+ <!DOCTYPE html
150
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
151
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
152
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
153
+ <head>
154
+ <title>RSpec results</title>
155
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
156
+ <meta http-equiv="Expires" content="-1" />
157
+ <meta http-equiv="Pragma" content="no-cache" />
158
+ <style type="text/css">
159
+ body {
160
+ margin: 0;
161
+ padding: 0;
162
+ background: #fff;
163
+ font-size: 80%;
164
+ }
165
+ </style>
166
+ <script type="text/javascript">
167
+ // <![CDATA[
168
+ #{global_scripts}
169
+ // ]]>
170
+ </script>
171
+ <style type="text/css">
172
+ #{global_styles}
173
+ </style>
174
+ </head>
175
+ <body>
176
+ EOF
177
+ end
178
+
179
+ def report_header
180
+ <<-EOF
181
+ <div class="rspec-report">
182
+
183
+ <div id="rspec-header">
184
+ <div id="label">
185
+ <h1>RSpec Code Examples</h1>
186
+ </div>
187
+
188
+ <div id="summary">
189
+ <p id="totals">&nbsp;</p>
190
+ <p id="duration">&nbsp;</p>
191
+ </div>
192
+ </div>
193
+
194
+ <div class="results">
195
+ EOF
196
+ end
197
+
198
+ def global_scripts
199
+ <<-EOF
200
+ function moveProgressBar(percentDone) {
201
+ document.getElementById("rspec-header").style.width = percentDone +"%";
202
+ }
203
+ function makeRed(element_id) {
204
+ document.getElementById(element_id).style.background = '#C40D0D';
205
+ document.getElementById(element_id).style.color = '#FFFFFF';
206
+ }
207
+
208
+ function makeYellow(element_id) {
209
+ if (element_id == "rspec-header" && document.getElementById(element_id).style.background != '#C40D0D')
210
+ {
211
+ document.getElementById(element_id).style.background = '#FAF834';
212
+ document.getElementById(element_id).style.color = '#000000';
213
+ }
214
+ else
215
+ {
216
+ document.getElementById(element_id).style.background = '#FAF834';
217
+ document.getElementById(element_id).style.color = '#000000';
218
+ }
219
+ }
220
+ EOF
221
+ end
222
+
223
+ def global_styles
224
+ <<-EOF
225
+ #rspec-header {
226
+ background: #65C400; color: #fff; height: 4em;
227
+ }
228
+
229
+ .rspec-report h1 {
230
+ margin: 0px 10px 0px 10px;
231
+ padding: 10px;
232
+ font-family: "Lucida Grande", Helvetica, sans-serif;
233
+ font-size: 1.8em;
234
+ position: absolute;
235
+ }
236
+
237
+ #summary {
238
+ margin: 0; padding: 5px 10px;
239
+ font-family: "Lucida Grande", Helvetica, sans-serif;
240
+ text-align: right;
241
+ top: 0px;
242
+ right: 0px;
243
+ float:right;
244
+ }
245
+
246
+ #summary p {
247
+ margin: 0 0 0 2px;
248
+ }
249
+
250
+ #summary #totals {
251
+ font-size: 1.2em;
252
+ }
253
+
254
+ .example_group {
255
+ margin: 0 10px 5px;
256
+ background: #fff;
257
+ }
258
+
259
+ dl {
260
+ margin: 0; padding: 0 0 5px;
261
+ font: normal 11px "Lucida Grande", Helvetica, sans-serif;
262
+ }
263
+
264
+ dt {
265
+ padding: 3px;
266
+ background: #65C400;
267
+ color: #fff;
268
+ font-weight: bold;
269
+ }
270
+
271
+ dd {
272
+ margin: 5px 0 5px 5px;
273
+ padding: 3px 3px 3px 18px;
274
+ }
275
+
276
+ dd.spec.passed {
277
+ border-left: 5px solid #65C400;
278
+ border-bottom: 1px solid #65C400;
279
+ background: #DBFFB4; color: #3D7700;
280
+ }
281
+
282
+ dd.spec.failed {
283
+ border-left: 5px solid #C20000;
284
+ border-bottom: 1px solid #C20000;
285
+ color: #C20000; background: #FFFBD3;
286
+ }
287
+
288
+ dd.spec.not_implemented {
289
+ border-left: 5px solid #FAF834;
290
+ border-bottom: 1px solid #FAF834;
291
+ background: #FCFB98; color: #131313;
292
+ }
293
+
294
+ dd.spec.pending_fixed {
295
+ border-left: 5px solid #0000C2;
296
+ border-bottom: 1px solid #0000C2;
297
+ color: #0000C2; background: #D3FBFF;
298
+ }
299
+
300
+ .backtrace {
301
+ color: #000;
302
+ font-size: 12px;
303
+ }
304
+
305
+ a {
306
+ color: #BE5C00;
307
+ }
308
+
309
+ /* Ruby code, style similar to vibrant ink */
310
+ .ruby {
311
+ font-size: 12px;
312
+ font-family: monospace;
313
+ color: white;
314
+ background-color: black;
315
+ padding: 0.1em 0 0.2em 0;
316
+ }
317
+
318
+ .ruby .keyword { color: #FF6600; }
319
+ .ruby .constant { color: #339999; }
320
+ .ruby .attribute { color: white; }
321
+ .ruby .global { color: white; }
322
+ .ruby .module { color: white; }
323
+ .ruby .class { color: white; }
324
+ .ruby .string { color: #66FF00; }
325
+ .ruby .ident { color: white; }
326
+ .ruby .method { color: #FFCC00; }
327
+ .ruby .number { color: white; }
328
+ .ruby .char { color: white; }
329
+ .ruby .comment { color: #9933CC; }
330
+ .ruby .symbol { color: white; }
331
+ .ruby .regex { color: #44B4CC; }
332
+ .ruby .punct { color: white; }
333
+ .ruby .escape { color: white; }
334
+ .ruby .interp { color: white; }
335
+ .ruby .expr { color: white; }
336
+
337
+ .ruby .offending { background-color: gray; }
338
+ .ruby .linenum {
339
+ width: 75px;
340
+ padding: 0.1em 1em 0.2em 0;
341
+ color: #000000;
342
+ background-color: #FFFBD3;
343
+ }
344
+ EOF
345
+ end
346
+ end
@@ -0,0 +1,17 @@
1
+ #=========================CODE COVERAGE========================
2
+ require './spec/cov_adapter'
3
+ SimpleCov.start 'cov'
4
+
5
+ #===========================REQUIRES===========================
6
+ require 'colored'
7
+ require 'json'
8
+ require 'rack'
9
+ require 'rspec'
10
+ require 'rack/test'
11
+
12
+ extend Colored
13
+
14
+ #==================SETUP TEST ENVIRONMENT======================
15
+ ENV['RACK_ENV'] = 'test'
16
+
17
+ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), ".."))
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ananke
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Andries Coetzee
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-07 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: sinatra
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 1.1.2
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: colored
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: "1.2"
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: json
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.5.1
47
+ type: :development
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: rack-test
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: 0.5.6
58
+ type: :development
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: rake
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.8.7
69
+ type: :development
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ version: 2.5.0
80
+ type: :development
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: simplecov
84
+ prerelease: false
85
+ requirement: &id007 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: 0.3.9
91
+ type: :development
92
+ version_requirements: *id007
93
+ description: Full REST Implementation on top of Sinatra
94
+ email: andriesc@mixtel.com
95
+ executables: []
96
+
97
+ extensions: []
98
+
99
+ extra_rdoc_files:
100
+ - README.rdoc
101
+ files:
102
+ - lib/ananke.rb
103
+ - lib/version.rb
104
+ - spec/cov_adapter.rb
105
+ - spec/lib/ananke_spec.rb
106
+ - spec/lib/validation_spec.rb
107
+ - spec/spec_helper.rb
108
+ - spec/nice_formatter.rb
109
+ - Gemfile
110
+ - Rakefile
111
+ - README.rdoc
112
+ has_rdoc: true
113
+ homepage: https://github.com/HasAndries/ananke
114
+ licenses: []
115
+
116
+ post_install_message: |
117
+ **************************************************
118
+
119
+ Thank you for installing ananke-0.0.1
120
+
121
+ Please be sure to look at README.rdoc to see what might have changed
122
+ since the last release and how to use this GEM.
123
+
124
+ **************************************************
125
+
126
+ rdoc_options:
127
+ - --charset=UTF-8
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: "0"
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: "0"
142
+ requirements: []
143
+
144
+ rubyforge_project:
145
+ rubygems_version: 1.5.0
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: ananke-0.0.1
149
+ test_files:
150
+ - spec/cov_adapter.rb
151
+ - spec/lib/ananke_spec.rb
152
+ - spec/lib/validation_spec.rb
153
+ - spec/spec_helper.rb
154
+ - spec/nice_formatter.rb