ki 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/.rvmrc +1 -1
  2. data/Gemfile +6 -3
  3. data/Gemfile.lock +81 -0
  4. data/Guardfile +9 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.rdoc +8 -1
  7. data/Rakefile +17 -3
  8. data/VERSION +1 -1
  9. data/bin/ki +3 -2
  10. data/examples/base/Gemfile +1 -7
  11. data/examples/base/Gemfile.lock +24 -0
  12. data/examples/base/app.rb +1 -2
  13. data/examples/base/config.ru +4 -0
  14. data/examples/{example → northpole}/Gemfile +0 -1
  15. data/examples/northpole/Gemfile.lock +33 -0
  16. data/examples/northpole/app.rb +19 -0
  17. data/examples/northpole/config.ru +6 -0
  18. data/examples/northpole/config.yml +3 -0
  19. data/examples/northpole/views/index.haml +1 -0
  20. data/examples/northpole/views/website.haml +1 -0
  21. data/ki.gemspec +125 -0
  22. data/lib/db.rb +43 -13
  23. data/lib/extensions/mail.rb +41 -0
  24. data/lib/helpers.rb +16 -0
  25. data/lib/ki.rb +8 -27
  26. data/lib/ki_cli.rb +63 -0
  27. data/lib/model.rb +59 -92
  28. data/lib/modules/callbacks.rb +27 -0
  29. data/lib/modules/query_interface.rb +29 -0
  30. data/lib/modules/restrictions.rb +62 -0
  31. data/lib/req.rb +30 -0
  32. data/lib/resp.rb +50 -0
  33. data/lib/static_file.rb +14 -0
  34. data/lib/util.rb +21 -30
  35. data/lib/views/404.haml +7 -0
  36. data/lib/views/406.haml +7 -0
  37. data/lib/views/index.haml +5 -17
  38. data/logo.png +0 -0
  39. data/spec/db_spec.rb +71 -0
  40. data/spec/ki_spec.rb +2 -2
  41. data/spec/model_spec.rb +82 -0
  42. data/spec/modules/callbacks_spec.rb +14 -0
  43. data/spec/modules/query_interface_spec.rb +63 -0
  44. data/spec/modules/restrictions_spec.rb +64 -0
  45. data/spec/req_spec.rb +4 -0
  46. data/spec/spec_helper.rb +30 -1
  47. data/spec/util_spec.rb +32 -16
  48. metadata +89 -36
  49. data/examples/base/config.yml +0 -3
  50. data/examples/example/app.rb +0 -15
  51. data/examples/example/config.ru +0 -2
  52. data/examples/example/config.yml +0 -3
  53. data/examples/example/public/custom.css +0 -0
  54. data/examples/example/public/custom.js +0 -0
  55. data/lib/cli.rb +0 -51
  56. data/lib/controller.rb +0 -15
  57. data/lib/modules.rb +0 -54
  58. data/lib/public/bootstrap.css +0 -6004
  59. data/lib/public/bootstrap.js +0 -2036
  60. data/lib/public/custom.css +0 -0
  61. data/lib/public/custom.js +0 -0
  62. data/lib/public/glyphicons-halflings-white.png +0 -0
  63. data/lib/public/glyphicons-halflings.png +0 -0
  64. data/lib/public/jquery-1.8.2.min.js +0 -2
  65. data/lib/public/ki.css +0 -56
  66. data/lib/request.rb +0 -14
  67. data/lib/response.rb +0 -51
  68. data/lib/views/container.haml +0 -6
  69. data/lib/views/footer.haml +0 -2
  70. data/lib/views/form.haml +0 -10
  71. data/lib/views/models.haml +0 -14
  72. data/lib/views/navbar.haml +0 -11
@@ -0,0 +1,27 @@
1
+ module Ki
2
+ module Callbacks
3
+ def before_find
4
+ end
5
+
6
+ def after_find
7
+ end
8
+
9
+ def before_create
10
+ end
11
+
12
+ def after_create
13
+ end
14
+
15
+ def before_update
16
+ end
17
+
18
+ def after_update
19
+ end
20
+
21
+ def before_delete
22
+ end
23
+
24
+ def after_delete
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,29 @@
1
+ module Ki
2
+ module QueryInterface
3
+ def count
4
+ Db.instance.db[class_name].count
5
+ end
6
+
7
+ def find id
8
+ Db.instance.find class_name, id
9
+ end
10
+
11
+ def create hash
12
+ Db.instance.create class_name, hash
13
+ end
14
+
15
+ def update hash
16
+ Db.instance.update class_name, hash
17
+ end
18
+
19
+ def delete id
20
+ Db.instance.delete class_name, id
21
+ end
22
+
23
+ private
24
+
25
+ def class_name
26
+ self.to_s.downcase
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,62 @@
1
+ module Ki
2
+ module Restrictions
3
+ def forbidden_actions
4
+ []
5
+ end
6
+
7
+ def forbid *actions
8
+ send :define_method, :forbidden_actions do
9
+ actions
10
+ end
11
+
12
+ eigen_class = class << self; self; end
13
+ eigen_class.send(:define_method, :forbidden_actions) do
14
+ actions
15
+ end
16
+ end
17
+
18
+ def allowed_formats
19
+ [:json, :html]
20
+ end
21
+
22
+ def respond_to *formats
23
+ send :define_method, :allowed_formats do
24
+ formats
25
+ end
26
+
27
+ eigen_class = class << self; self; end
28
+ eigen_class.send(:define_method, :allowed_formats) do
29
+ formats
30
+ end
31
+ end
32
+
33
+ def required_attributes
34
+ []
35
+ end
36
+
37
+ def requires *attributes
38
+ send :define_method, :required_attributes do
39
+ attributes
40
+ end
41
+
42
+ eigen_class = class << self; self; end
43
+ eigen_class.send(:define_method, :required_attributes) do
44
+ attributes
45
+ end
46
+ end
47
+ end
48
+
49
+ module InitRestrictions
50
+ def forbidden_actions
51
+ []
52
+ end
53
+
54
+ def allowed_formats
55
+ [:json, :html]
56
+ end
57
+
58
+ def required_attributes
59
+ []
60
+ end
61
+ end
62
+ end
data/lib/req.rb ADDED
@@ -0,0 +1,30 @@
1
+ module Ki
2
+ class Req < Rack::Request
3
+ attr_accessor :code, :klass, :format
4
+
5
+ def initialize env
6
+ super env
7
+ end
8
+
9
+ def serve
10
+ unless static_path_requested?
11
+ route
12
+ Resp.new(self).finish
13
+ else
14
+ StaticFile.new(self).finish
15
+ end
16
+ end
17
+
18
+ def route
19
+ @klass = Util.base(path).to_class
20
+ @format = Util.format(path)
21
+ @code = klass || path == '/' ? 200 : 404
22
+ end
23
+
24
+ private
25
+
26
+ def static_path_requested?
27
+ path.start_with? '/public/'
28
+ end
29
+ end
30
+ end
data/lib/resp.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'json'
2
+
3
+ module Ki
4
+ class Resp < Rack::Response
5
+ include Helpers
6
+
7
+ attr_accessor :req
8
+
9
+ def initialize req
10
+ @req = req
11
+ headers = {
12
+ 'Content-Type' => respond_to(@req.format)
13
+ }
14
+
15
+ klass = @req.klass
16
+ if klass.allowed_formats.include? @req.format
17
+ if @req.code == 404
18
+ body = @req.format == :html ? partial('404') : { :error => 404 }
19
+ else
20
+ if @req.path == '/'
21
+ body = @req.format == :html ? partial('index') : { :index => 200 }
22
+ else
23
+ klass_view = Util.root_view_path(klass.to_s.downcase)
24
+ if @req.format == :html
25
+ body = File.exists?(klass_view) ? partial(klass.to_s.downcase) : partial('index')
26
+ else
27
+ begin
28
+ body = klass.new(@req).to_json
29
+ rescue Exception => e
30
+ @req.code = 400
31
+ body = { :error => e.to_s }.to_json
32
+ end
33
+ end
34
+ end
35
+ end
36
+ else
37
+ @req.code = 406
38
+ body = @req.format == :html ? partial('406') : { :error => 'format not allowed' }.to_json
39
+ end
40
+
41
+ super [body], @req.code, headers
42
+ end
43
+
44
+ private
45
+
46
+ def respond_to resp
47
+ resp == :html ? 'text/html' : 'application/json'
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,14 @@
1
+ module Ki
2
+ class StaticFile < Rack::File
3
+ attr_reader :env
4
+
5
+ def initialize req
6
+ super Util.root
7
+ @env = req.env
8
+ end
9
+
10
+ def finish
11
+ call(@env)
12
+ end
13
+ end
14
+ end
data/lib/util.rb CHANGED
@@ -1,3 +1,9 @@
1
+ class NilClass
2
+ def allowed_formats
3
+ [:json, :html]
4
+ end
5
+ end
6
+
1
7
  class String
2
8
  def to_class
3
9
  chain = self.split "::"
@@ -13,22 +19,6 @@ end
13
19
 
14
20
  module Ki
15
21
  class Util
16
- # the order in which files are loaded is important
17
- def self.static_files
18
- static_files = Dir.glob(File.join(Ki.root, 'lib/public/*'))
19
- static_files << Dir.glob(File.join(Dir.pwd, 'public/*'))
20
- static_files.flatten!
21
- end
22
-
23
- def self.partial s, hash={}
24
- path = File.join(Dir.pwd, 'views', s) + '.haml'
25
- unless File.exists? path
26
- path = File.join(Ki.root, 'lib', 'views', s) + '.haml'
27
- end
28
- contents = File.read(path)
29
- Haml::Engine.new(contents).render(Object.new(), hash)
30
- end
31
-
32
22
  def self.base s
33
23
  if s == '/'
34
24
  return ''
@@ -52,19 +42,8 @@ module Ki
52
42
  end
53
43
  end
54
44
 
55
- def self.config_db
56
- config_path = File.join(Dir.pwd, 'config.yml')
57
- yaml = {}
58
- if File.exists? config_path
59
- yaml = YAML.load_file(config_path)
60
- else
61
- yaml = {
62
- 'host' => '127.0.0.1',
63
- 'port' => 27017,
64
- 'db_name' => 'ki'
65
- }
66
- end
67
- Db.instance.config yaml['host'], yaml['port'], yaml['db_name']
45
+ def self.root_view_path name
46
+ File.join(root, 'views', name) + '.haml'
68
47
  end
69
48
 
70
49
  def self.format s
@@ -74,10 +53,22 @@ module Ki
74
53
 
75
54
  base = s.split('/')[1]
76
55
  if base.include? '.'
77
- base.split('.')[1].split('?')[0].to_sym
56
+ base.split('.')[1].split('?')[0].to_sym rescue :html
78
57
  else
79
58
  :html
80
59
  end
81
60
  end
61
+
62
+ def self.src_path
63
+ File.join(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
64
+ end
65
+
66
+ def self.root
67
+ Dir.getwd
68
+ end
69
+
70
+ def self.app_name
71
+ File.basename(root)
72
+ end
82
73
  end
83
74
  end
@@ -0,0 +1,7 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title 404 - Not Found
5
+ %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"}
6
+ %body
7
+ %center 404 - Not Found
@@ -0,0 +1,7 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title 406 - Not Acceptable Format
5
+ %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"}
6
+ %body
7
+ %center 406 - Not Acceptable Format
data/lib/views/index.haml CHANGED
@@ -1,19 +1,7 @@
1
- !!! 5
2
- %html{:lang => "en"}
1
+ !!!
2
+ %html
3
3
  %head
4
- %meta{:charset => "utf-8"}
5
- %title= "#{Ki::Ki.app_name} - #{req.klass.to_s}"
6
- %meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
7
- %meta{:content => "", :name => "description"}
8
- %meta{:content => "", :name => "author"}
9
-
10
- %link{:href => "/public/bootstrap.css", :rel => "stylesheet"}
11
- %link{:href => "/public/ki.css", :rel => "stylesheet"}
12
- %link{:href => "/public/custom.css", :rel => "stylesheet"}
4
+ %title 200 - Hello World
5
+ %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"}
13
6
  %body
14
-
15
- = Ki::Util.partial 'container', locals
16
-
17
- %script{:src => "/public/jquery-1.8.2.min.js"}
18
- %script{:src => "/public/bootstrap.js"}
19
- %script{:src => "/public/custom.js"}
7
+ %center 200 - Hello World
data/logo.png ADDED
Binary file
data/spec/db_spec.rb ADDED
@@ -0,0 +1,71 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Ki::Db do
4
+ before :each do
5
+ @db = Ki::Db.instance
6
+ @db.remove_collections
7
+ end
8
+
9
+ it "should start with an empty database" do
10
+ @db.collection_names.empty?.should be_true
11
+ end
12
+
13
+ it "should create a collection" do
14
+ @db.collection_names.empty?.should be_true
15
+ @db.create 'zoidberg', { :foo => 'bar' }
16
+ @db.collection_names.empty?.should be_false
17
+ @db.collection_names.include?('zoidberg').should be_true
18
+ end
19
+
20
+ it "should create an model" do
21
+ @db.db['zoidberg'].count.should == 0
22
+ @db.create 'zoidberg', { :foo => [1,2] }
23
+ @db.db['zoidberg'].count.should == 1
24
+ end
25
+
26
+ it "should return doc id when creating a model" do
27
+ post_id = @db.create 'zoidberg', { :foo => [1,2] }
28
+ post_id.class.should == String
29
+ bson_id = BSON::ObjectId.from_string(post_id)
30
+ @db.db['zoidberg'].find('_id' => bson_id).first['foo'].should == [1,2]
31
+ end
32
+
33
+ it "should find a specific document" do
34
+ post_id = @db.create 'zoidberg', { :foo => [1,2] }
35
+ @db.find('zoidberg', post_id)['foo'].should == [1,2]
36
+ end
37
+
38
+ it "should update a document" do
39
+ post_id = @db.create 'zoidberg', { :foo => [1,2], :bar => 'highj' }
40
+ @db.update 'zoidberg', { '_id' => post_id, :foo => 3.1415 }
41
+ doc = @db.find('zoidberg', post_id)
42
+ doc['foo'].should == 3.1415
43
+ doc['bar'].should == nil
44
+ end
45
+
46
+ it "should delete a document" do
47
+ post_id = @db.create 'zoidberg', { :foo => [1,2], :bar => 'highj' }
48
+ @db.db['zoidberg'].count.should == 1
49
+ @db.delete('zoidberg', post_id)
50
+ @db.db['zoidberg'].count.should == 0
51
+ end
52
+
53
+ it "should find all documents in collection" do
54
+ @db.create 'zoidberg', { :foo => [1,2], :bar => 'highj' }
55
+ @db.create 'zoidberg', { :foo => [3,4], :bar => 'lowj' }
56
+ @db.find_all('zoidberg').count.should == @db.db['zoidberg'].count
57
+ end
58
+
59
+ it "should find by an attribute" do
60
+ @db.create 'zoidberg', { :foo => [1,2], :bar => 'highj' }
61
+ @db.create 'zoidberg', { :foo => [3,4], :bar => 'lowj' }
62
+ @db.create 'zoidberg', { :foo => [5,6], :bar => 'lowj' }
63
+ r = @db.find_by 'zoidberg', { :bar => 'lowj' }
64
+ r.class.should == Array
65
+ r.length.should == 2
66
+
67
+ r = @db.find_by 'zoidberg', { :bar => 'lowj', :foo => [3,4] }
68
+ r.class.should == Array
69
+ r.length.should == 1
70
+ end
71
+ end
data/spec/ki_spec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe "Ki" do
4
- it "works" do
3
+ describe Ki do
4
+ it "should work" do
5
5
  1.should == 1
6
6
  end
7
7
  end
@@ -0,0 +1,82 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Ki::Model do
4
+ before :each do
5
+ class Zoidberg < Ki::Model
6
+ end
7
+ @db = Ki::Db.instance
8
+ @db.remove_collections
9
+ end
10
+
11
+ it "should correctly extract class_name" do
12
+ # Zoidberg.new(@get).class_name.should == "zoidberg"
13
+ end
14
+
15
+ it "should create a new item in the databse" do
16
+ post = ReqFactory.new(:post_homer)
17
+ @db.db['zoidberg'].count.should == 0
18
+ hash = Zoidberg.new(post).hash
19
+ @db.db['zoidberg'].count.should == 1
20
+ @db.find('zoidberg', hash['_id'])['user'].should == 'homer'
21
+ end
22
+
23
+ it "should get a model depending on id" do
24
+ id = @db.create 'zoidberg', { :name => 'homer' }
25
+
26
+ get = ReqFactory.new(:get, {'_id' => id})
27
+ Zoidberg.new(get).hash['name'].should == 'homer'
28
+ end
29
+
30
+ it "should raise error if no params are given when getting model" do
31
+ expect {
32
+ Zoidberg.new(ReqFactory.new(:get))
33
+ }.to raise_error
34
+ end
35
+
36
+ it "should raise error if no id is given when getting model" do
37
+ expect {
38
+ Zoidberg.new(ReqFactory.new(:get_with_params, { :name => 'homer' }))
39
+ }.to raise_error
40
+ end
41
+
42
+ it "should only accept valid object ids" do
43
+ expect {
44
+ Zoidberg.new(ReqFactory.new(:get_with_params, { :_id => 'homer' }))
45
+ }.to raise_error
46
+ end
47
+
48
+ it "should update a document" do
49
+ id = @db.create 'zoidberg', { :name => 'homer' }
50
+ @db.find('zoidberg', id)['name'].should == 'homer'
51
+
52
+ Zoidberg.new(ReqFactory.new(:put, {'_id' => id, :name => 'bart'}))
53
+ @db.find('zoidberg', id)['name'].should == 'bart'
54
+ end
55
+
56
+ it "should raise error if id is missing when updating" do
57
+ expect {
58
+ Zoidberg.new(ReqFactory.new(:put, {:name => 'bart'}))
59
+ }.to raise_error
60
+ end
61
+
62
+ it "should raise error if id is invalid" do
63
+ expect {
64
+ Zoidberg.new(ReqFactory.new(:put, {'_id' => 'f*ck', :name => 'bart'}))
65
+ }.to raise_error
66
+ end
67
+
68
+ it "should delete a document" do
69
+ expect {
70
+ Zoidberg.new(ReqFactory.new(:delete))
71
+ }.to raise_error
72
+
73
+ expect {
74
+ Zoidberg.new(ReqFactory.new(:delete, {'_id' => 'f*ck', :name => 'bart'}))
75
+ }.to raise_error
76
+
77
+ id = @db.create 'zoidberg', { :name => 'homer' }
78
+ expect {
79
+ Zoidberg.new(ReqFactory.new(:delete, {'_id' => id}))
80
+ }.to change(@db.db['zoidberg'], :count).by(-1)
81
+ end
82
+ end