yodatra 0.1.4 → 0.1.5

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'sinatra-activerecord', :git => 'git://github.com/popox/sinatra-activerecord'
3
+ group :test do
4
+ gem 'rake'
5
+ gem 'rspec', :require => false
6
+ gem 'simplecov', :require => false
7
+ gem 'coveralls', :require => false
8
+ gem 'mocha', :require => false
9
+ end
4
10
 
5
11
  gemspec
data/README.md ADDED
@@ -0,0 +1,6 @@
1
+ Yodatra [![Build Status](https://travis-ci.org/squareteam/yodatra.png?branch=master)](https://travis-ci.org/squareteam/yodatra) [![Coverage Status](https://coveralls.io/repos/squareteam/yodatra/badge.png)](https://coveralls.io/r/squareteam/yodatra)
2
+ ===
3
+
4
+ Backend development you shall do. And yodatra you shall use.
5
+
6
+ A minimalistic framework built on top of Sinatra it is.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new do |task|
5
+ task.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
6
+ task.pattern = 'spec/**/*_spec.rb'
7
+ end
8
+
9
+ require 'coveralls/rake/task'
10
+ Coveralls::RakeTask.new
11
+ task :test_with_coveralls => [:spec, :features, 'coveralls:push']
12
+
13
+ task :default => :spec
@@ -13,7 +13,7 @@ module Yodatra
13
13
  def _call(env)
14
14
  status, headers, response = @app.call(env)
15
15
 
16
- @block.yield status, headers, response unless @block.nil?
16
+ status, headers, response = @block.yield(status, headers, response) unless @block.nil?
17
17
 
18
18
  [status, headers, response]
19
19
  end
@@ -0,0 +1,26 @@
1
+ module Yodatra
2
+ class Crypto
3
+
4
+ class << self
5
+ # Computes the PBKDF2-SHA256 digest of a password using 10000 iterations and
6
+ # the given salt, and return a 32-byte output. If no salt is given, a random
7
+ # 8-byte salt is generated. The salt is also returned.
8
+ def generate_pbkdf(password, salt = nil)
9
+ new_salt = salt
10
+ iter = 1000
11
+
12
+ if salt.nil?
13
+ new_salt = SecureRandom.random_bytes(8)
14
+ end
15
+
16
+ digest = OpenSSL::Digest::SHA256.new
17
+ len = digest.digest_length
18
+ value = OpenSSL::PKCS5.pbkdf2_hmac(password, new_salt, iter, len, digest)
19
+
20
+ [new_salt, value]
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,100 @@
1
+ module Yodatra
2
+ class ModelController < Sinatra::Base
3
+
4
+ before do
5
+ content_type 'application/json'
6
+ end
7
+
8
+ READ_ALL = :read_all
9
+ get "/*s" do
10
+ no_route if disabled? READ_ALL
11
+ model_name.constantize.all.to_json
12
+ end
13
+
14
+ READ_ONE = :read
15
+ get "/*s/:id" do
16
+ no_route if disabled? READ_ONE
17
+
18
+ @one = model_name.constantize.find params[:id]
19
+ @one.to_json
20
+ end
21
+
22
+ CREATE_ONE = :create
23
+ post "/*s" do
24
+ no_route if disabled? CREATE_ONE
25
+
26
+ @one = model_name.constantize.new params
27
+
28
+ if @one.save
29
+ @one.to_json
30
+ else
31
+ status 400
32
+ @one.errors.full_messages.to_json
33
+ end
34
+ end
35
+
36
+ UPDATE_ONE = :update
37
+ put "/*s/:id" do
38
+ no_route if disabled? UPDATE_ONE
39
+
40
+ @one = model_name.constantize.find params[:id]
41
+
42
+ if !@one.nil? && @one.update_attributes(params)
43
+ @one.to_json
44
+ else
45
+ status 400
46
+ if !@one.nil?
47
+ @one.errors.full_messages.to_json
48
+ else
49
+ ['record not found'].to_json
50
+ end
51
+ end
52
+ end
53
+
54
+ DELETE_ONE = :delete
55
+ delete "/*s/:id" do
56
+ no_route if disabled? DELETE_ONE
57
+
58
+ @one = model_name.constantize.find params[:id]
59
+
60
+ if @one.destroy
61
+ @one.to_json
62
+ else
63
+ status 400
64
+ @one.errors.full_messages.to_json
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def model_params
71
+ params
72
+ end
73
+
74
+ def model_name
75
+ self.class.name.split('::').last.gsub(/sController/, '')
76
+ end
77
+
78
+ def route_name
79
+ self.send(:model_name).underscore
80
+ end
81
+
82
+ def disabled? key
83
+ params[:splat].first != route_name || self.class.method_defined?(key) && self.send(key)
84
+ end
85
+
86
+ def no_route
87
+ pass
88
+ end
89
+
90
+ class << self
91
+ def disable(*opts)
92
+ opts.each do |key|
93
+ undef_method(key) if method_defined? key
94
+ define_method(key, Proc.new {|| true})
95
+ end
96
+ end
97
+ end
98
+
99
+ end
100
+ end
@@ -1,3 +1,3 @@
1
1
  module Yodatra
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.5'
3
3
  end
@@ -0,0 +1,24 @@
1
+ ENV['RACK_ENV'] ||= 'test'
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ require 'coveralls'
5
+ Coveralls.wear!
6
+ require 'rack/test'
7
+ require 'rspec'
8
+
9
+ require File.expand_path '../../lib/yodatra.rb', __FILE__
10
+ require File.expand_path '../../lib/yodatra/model_controller.rb', __FILE__
11
+
12
+ module RSpecMixin
13
+ include Rack::Test::Methods
14
+ def app
15
+ Sinatra.new {
16
+ use Yodatra::Base
17
+ use Yodatra::ModelController
18
+ }
19
+ end
20
+ end
21
+
22
+ RSpec.configure do |c|
23
+ c.include RSpecMixin
24
+ end
@@ -0,0 +1,148 @@
1
+ require File.expand_path '../../spec_helper.rb', __FILE__
2
+ require 'mocha/setup'
3
+ require 'mocha/api'
4
+
5
+ # Mock model constructed for the tests
6
+ class TestModel
7
+ ALL = %w(a b c)
8
+ class << self
9
+ def all; ALL.map{ |e| TestModel.new({:data=> e }) }; end
10
+ def find(id); TestModel.new({:data => ALL[id.to_i]}); end
11
+ end
12
+ def initialize(param); @data = param[:data]; end
13
+ def save
14
+ if @data.is_a? String
15
+ ALL.push(@data)
16
+ true
17
+ else
18
+ false
19
+ end
20
+ end
21
+ def destroy
22
+ if ALL.include? @data
23
+ ALL.delete @data
24
+ true
25
+ else
26
+ false
27
+ end
28
+ end
29
+ def errors; []; end
30
+ end
31
+
32
+ describe 'Model controller' do
33
+ before do
34
+ @any_model = 'TestModel'
35
+ @errors = ['error']
36
+ Yodatra::ModelController.any_instance.stubs(:model_name).returns(@any_model)
37
+ Array.any_instance.stubs(:full_messages).returns(@errors)
38
+ end
39
+
40
+ describe 'Getting a collection of the Model' do
41
+ context 'default' do
42
+ it 'should have a GET all route' do
43
+ get '/test_models'
44
+
45
+ last_response.should be_ok
46
+ expect(last_response.body).to eq(TestModel::ALL.map{|e| {:data => e} }.to_json)
47
+ end
48
+ end
49
+ context 'forced GET all route disabled' do
50
+ before do
51
+ class Yodatra::ModelController
52
+ disable :read_all
53
+ end
54
+ end
55
+ it 'should fail with no route available' do
56
+ get '/test_models'
57
+
58
+ last_response.should_not be_ok
59
+ end
60
+ end
61
+ end
62
+ describe 'getting an specific Model instance' do
63
+ it 'should have a GET one route' do
64
+ get '/test_models/2'
65
+
66
+ last_response.should be_ok
67
+ expect(last_response.body).to eq({ :data => 'c'}.to_json)
68
+ end
69
+ context 'forced GET one route disabled' do
70
+ before do
71
+ class Yodatra::ModelController
72
+ disable :read
73
+ end
74
+ end
75
+ it 'should fail with no route available' do
76
+ get '/test_models/1'
77
+
78
+ last_response.should_not be_ok
79
+ end
80
+ end
81
+ end
82
+ describe 'creating a Model instance' do
83
+ context 'with correct model params' do
84
+ it 'adds creates an instance, saves it and succeed' do
85
+ expect{
86
+ post '/test_models', {:data => 'd'}
87
+ }.to change(TestModel::ALL, :length).by(1)
88
+
89
+ last_response.should be_ok
90
+ end
91
+ end
92
+ context 'with incorrect params' do
93
+ it 'doesn t create an instance and fails' do
94
+ expect{
95
+ post '/test_models', {}
96
+ }.to change(TestModel::ALL, :length).by(0)
97
+
98
+ last_response.should_not be_ok
99
+ expect(last_response.body).to eq(@errors.to_json)
100
+ end
101
+ end
102
+ context 'when the creation route is disabled' do
103
+ before do
104
+ class Yodatra::ModelController
105
+ disable :create
106
+ end
107
+ end
108
+ it 'should fail with no route available' do
109
+ post '/test_models', {:data => 'd'}
110
+
111
+ last_response.should_not be_ok
112
+ end
113
+ end
114
+ end
115
+ describe 'deleting a Model instance' do
116
+ context 'targeting an existing instance' do
117
+ it 'deletes the instance and succeed' do
118
+ expect{
119
+ delete '/test_models/1'
120
+ }.to change(TestModel::ALL, :length).by(-1)
121
+
122
+ last_response.should be_ok
123
+ end
124
+ end
125
+ context 'targeting a not existing instance' do
126
+ it 'does not delete any instance and fails' do
127
+ expect{
128
+ delete '/test_models/6'
129
+ }.to change(TestModel::ALL, :length).by(0)
130
+
131
+ last_response.should_not be_ok
132
+ end
133
+ end
134
+ context 'when the deletion route is disabled' do
135
+ before do
136
+ class Yodatra::ModelController
137
+ disable :delete
138
+ end
139
+ end
140
+ it 'should fail with no route available' do
141
+ delete '/test_models/2'
142
+
143
+ last_response.should_not be_ok
144
+ end
145
+ end
146
+ end
147
+
148
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yodatra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-02 00:00:00.000000000 Z
12
+ date: 2014-02-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -124,19 +124,24 @@ email: paul+st@bonaud.fr
124
124
  executables: []
125
125
  extensions: []
126
126
  extra_rdoc_files:
127
- - README
127
+ - README.md
128
128
  - LICENSE
129
129
  files:
130
130
  - Gemfile
131
131
  - LICENSE
132
- - README
132
+ - README.md
133
+ - Rakefile
133
134
  - lib/yodatra.rb
134
135
  - lib/yodatra/api_formatter.rb
135
136
  - lib/yodatra/base.rb
136
137
  - lib/yodatra/boot.rb
138
+ - lib/yodatra/crypto.rb
137
139
  - lib/yodatra/initializers.rb
138
140
  - lib/yodatra/logger.rb
141
+ - lib/yodatra/model_controller.rb
139
142
  - lib/yodatra/version.rb
143
+ - spec/spec_helper.rb
144
+ - spec/unit/model_controller_spec.rb
140
145
  - yodatra.gemspec
141
146
  homepage: http://squareteam.github.io/yodatra
142
147
  licenses:
@@ -170,4 +175,5 @@ rubygems_version: 1.8.25
170
175
  signing_key:
171
176
  specification_version: 3
172
177
  summary: Classy backend development with the speed of Sinatra and the power of ActiveRecord
173
- test_files: []
178
+ test_files:
179
+ - spec/unit/model_controller_spec.rb
data/README DELETED
@@ -1,6 +0,0 @@
1
- Yodatra
2
- ===
3
-
4
- Backend development you shall do. And yodatra you shall use.
5
-
6
- A minimalistic framework built on top of Sinatra it is.