ki 0.0.2 → 0.1.0

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