yodatra 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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.