garrison 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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/Gemfile +14 -0
  4. data/Gemfile.lock +141 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +3 -0
  7. data/Rakefile +21 -0
  8. data/garrison.gemspec +30 -0
  9. data/lib/garrison.rb +34 -0
  10. data/lib/garrison/checker_abstract.rb +22 -0
  11. data/lib/garrison/injectee.rb +19 -0
  12. data/lib/garrison/keeper.rb +34 -0
  13. data/lib/garrison/locking_active_record.rb +20 -0
  14. data/lib/garrison/version.rb +3 -0
  15. data/lib/tasks/garrison_tasks.rake +4 -0
  16. data/spec/dummy/README.rdoc +28 -0
  17. data/spec/dummy/Rakefile +6 -0
  18. data/spec/dummy/app/assets/images/.keep +0 -0
  19. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  20. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  21. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  22. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  23. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  24. data/spec/dummy/app/mailers/.keep +0 -0
  25. data/spec/dummy/app/models/.keep +0 -0
  26. data/spec/dummy/app/models/concerns/.keep +0 -0
  27. data/spec/dummy/app/models/model_a.rb +2 -0
  28. data/spec/dummy/app/models/model_b.rb +2 -0
  29. data/spec/dummy/app/models/model_c.rb +2 -0
  30. data/spec/dummy/app/models/user.rb +2 -0
  31. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  32. data/spec/dummy/bin/bundle +3 -0
  33. data/spec/dummy/bin/rails +4 -0
  34. data/spec/dummy/bin/rake +4 -0
  35. data/spec/dummy/config.ru +4 -0
  36. data/spec/dummy/config/application.rb +38 -0
  37. data/spec/dummy/config/boot.rb +5 -0
  38. data/spec/dummy/config/environment.rb +5 -0
  39. data/spec/dummy/config/environments/development.rb +29 -0
  40. data/spec/dummy/config/environments/production.rb +80 -0
  41. data/spec/dummy/config/environments/test.rb +36 -0
  42. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  43. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  44. data/spec/dummy/config/initializers/inflections.rb +16 -0
  45. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  46. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  47. data/spec/dummy/config/initializers/session_store.rb +3 -0
  48. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  49. data/spec/dummy/config/locales/en.yml +23 -0
  50. data/spec/dummy/config/routes.rb +56 -0
  51. data/spec/dummy/db/migrate/20160612023105_create_model_as.rb +9 -0
  52. data/spec/dummy/db/migrate/20160612023109_create_model_bs.rb +9 -0
  53. data/spec/dummy/db/migrate/20160612025050_create_model_cs.rb +9 -0
  54. data/spec/dummy/db/migrate/20160612033904_create_users.rb +9 -0
  55. data/spec/dummy/db/schema.rb +40 -0
  56. data/spec/dummy/lib/assets/.keep +0 -0
  57. data/spec/dummy/log/.keep +0 -0
  58. data/spec/dummy/public/404.html +58 -0
  59. data/spec/dummy/public/422.html +58 -0
  60. data/spec/dummy/public/500.html +57 -0
  61. data/spec/dummy/public/favicon.ico +0 -0
  62. data/spec/dummy/spec/factories/model_as.rb +5 -0
  63. data/spec/dummy/spec/factories/model_bs.rb +5 -0
  64. data/spec/dummy/spec/factories/model_cs.rb +5 -0
  65. data/spec/dummy/spec/factories/users.rb +5 -0
  66. data/spec/dummy/spec/models/model_a_spec.rb +5 -0
  67. data/spec/dummy/spec/models/model_b_spec.rb +5 -0
  68. data/spec/dummy/spec/models/model_c_spec.rb +5 -0
  69. data/spec/dummy/spec/models/user_spec.rb +5 -0
  70. data/spec/garrison/base_spec.rb +56 -0
  71. data/spec/garrison/keeper_spec.rb +138 -0
  72. data/spec/rails_helper.rb +65 -0
  73. data/spec/spec_helper.rb +92 -0
  74. metadata +241 -0
@@ -0,0 +1,9 @@
1
+ class CreateModelAs < ActiveRecord::Migration
2
+ def change
3
+ create_table :model_as do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class CreateModelBs < ActiveRecord::Migration
2
+ def change
3
+ create_table :model_bs do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class CreateModelCs < ActiveRecord::Migration
2
+ def change
3
+ create_table :model_cs do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 20160612033904) do
15
+
16
+ create_table "model_as", force: true do |t|
17
+ t.string "name"
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ end
21
+
22
+ create_table "model_bs", force: true do |t|
23
+ t.string "name"
24
+ t.datetime "created_at"
25
+ t.datetime "updated_at"
26
+ end
27
+
28
+ create_table "model_cs", force: true do |t|
29
+ t.string "name"
30
+ t.datetime "created_at"
31
+ t.datetime "updated_at"
32
+ end
33
+
34
+ create_table "users", force: true do |t|
35
+ t.string "name"
36
+ t.datetime "created_at"
37
+ t.datetime "updated_at"
38
+ end
39
+
40
+ end
File without changes
File without changes
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/404.html -->
52
+ <div class="dialog">
53
+ <h1>The page you were looking for doesn't exist.</h1>
54
+ <p>You may have mistyped the address or the page may have moved.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/422.html -->
52
+ <div class="dialog">
53
+ <h1>The change you wanted was rejected.</h1>
54
+ <p>Maybe you tried to change something you didn't have access to.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/500.html -->
52
+ <div class="dialog">
53
+ <h1>We're sorry, but something went wrong.</h1>
54
+ </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
56
+ </body>
57
+ </html>
File without changes
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :model_a do
3
+ name "MyString"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :model_b do
3
+ name "MyString"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :model_c do
3
+ name "MyString"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :user do
3
+ name "MyString"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe ModelA, type: :model do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe ModelB, type: :model do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe ModelC, type: :model do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe User, type: :model do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
@@ -0,0 +1,56 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Garrison do
4
+ before { Garrison.lock! ModelA, ModelC }
5
+
6
+ describe 'define methods' do
7
+ context 'target class' do
8
+ subject { ModelA.method_defined? :garrison }
9
+ it { should be_truthy }
10
+ end
11
+
12
+ context 'not target class' do
13
+ subject { ModelB.method_defined? :garrison }
14
+ it { should be_truthy }
15
+ end
16
+ end
17
+
18
+ describe 'lock automatically' do
19
+ context 'target class' do
20
+ describe 'locked' do
21
+ let(:model) { ModelA.new(name: 'user') }
22
+ subject { model.garrison.locked? }
23
+ it { should be_truthy }
24
+ end
25
+
26
+ describe 'save' do
27
+ let(:model) { ModelA.new(name: 'user') }
28
+ subject { model.save }
29
+ it { expect { should }.to raise_error(Garrison::Locked) }
30
+ end
31
+ end
32
+
33
+ context 'not target class' do
34
+ describe 'locked' do
35
+ let(:model) { ModelB.create!(name: 'user', garrison_locked: false) }
36
+ subject { model.garrison.locked? }
37
+ it { should be_falsey }
38
+ end
39
+
40
+ describe 'save' do
41
+ let(:model) { ModelB.create!(name: 'user', garrison_locked: false) }
42
+ subject { model.save }
43
+ it { should be_truthy }
44
+ end
45
+ end
46
+ end
47
+
48
+ describe 'unlock' do
49
+ context 'target class' do
50
+ let(:model) { ModelA.create!(name: 'user', garrison_locked: false) }
51
+ subject { model.save }
52
+ before { model.garrison.unlock }
53
+ it { should be_truthy }
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,138 @@
1
+ require 'rails_helper'
2
+
3
+ module Garrison
4
+ RSpec.describe Keeper do
5
+ before { Garrison.lock! ModelA, ModelC }
6
+ let(:user) { User.create!(name: 'user') }
7
+
8
+ describe 'check' do
9
+ context 'enable' do
10
+ let(:model) { ModelA.create!(name: 'user', garrison_locked: false) }
11
+ let(:keeper) { Keeper.new(user) }
12
+
13
+ it 'read' do
14
+ read = false
15
+ keeper.read(model) { read = true }
16
+ expect(read).to be_truthy
17
+ end
18
+
19
+ it 'other read' do
20
+ read = false
21
+ keeper.read_other(model) { read = true }
22
+ expect(read).to be_truthy
23
+ end
24
+
25
+ it 'write' do
26
+ written = false
27
+ keeper.write(model) { written = model.save }
28
+ expect(written).to be_truthy
29
+ end
30
+
31
+ it 'other write' do
32
+ written = false
33
+ keeper.write_other(model, writable: true) { written = model.save }
34
+ expect(written).to be_truthy
35
+ end
36
+ end
37
+
38
+ context 'disable' do
39
+ let(:model) { ModelC.create!(name: 'user', garrison_locked: false) }
40
+ let(:keeper) { Keeper.new(user) }
41
+
42
+ it 'read' do
43
+ expect {
44
+ keeper.read(model)
45
+ }.to raise_error(Garrison::Forbidden)
46
+ end
47
+
48
+ it 'write' do
49
+ expect {
50
+ keeper.write(model)
51
+ }.to raise_error(Garrison::Forbidden)
52
+ end
53
+ end
54
+
55
+ context 'return result' do
56
+ let(:model) { ModelA.create!(name: 'user', garrison_locked: false) }
57
+ let(:keeper) { Keeper.new(user) }
58
+
59
+ it 'read' do
60
+ result = keeper.read(model) do
61
+ model.name
62
+ :abc
63
+ end
64
+
65
+ expect(result).to eq(:abc)
66
+ end
67
+
68
+ it 'write' do
69
+ result = keeper.write(model) do
70
+ model.save
71
+ :abc
72
+ end
73
+
74
+ expect(result).to eq(:abc)
75
+ end
76
+ end
77
+ end
78
+
79
+ describe 'auto lock' do
80
+ let(:model) { ModelA.create!(name: 'user', garrison_locked: false) }
81
+ let(:keeper) { Keeper.new(user) }
82
+ subject { model.save }
83
+
84
+ context 'after create' do
85
+ it do
86
+ expect { should }.to raise_error(Garrison::Locked)
87
+ end
88
+ end
89
+
90
+ context 'after read' do
91
+ it do
92
+ keeper.read(model)
93
+ expect { should }.to raise_error(Garrison::Locked)
94
+ end
95
+ end
96
+
97
+ context 'after wrote' do
98
+ it do
99
+ keeper.write(model)
100
+ expect { should }.to raise_error(Garrison::Locked)
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ class ModelAChecker < CheckerAbstract
107
+ def can_read?
108
+ user.name == obj.name
109
+ end
110
+
111
+ def can_write?
112
+ user.name == obj.name
113
+ end
114
+
115
+ def can_read_other?
116
+ user.name == obj.name
117
+ end
118
+
119
+ def can_write_other?
120
+ user.name == obj.name
121
+ end
122
+
123
+ def can_write_disabled?
124
+ user.name != obj.name
125
+ end
126
+ end
127
+
128
+ class ModelCChecker < CheckerAbstract
129
+ def can_read?
130
+ false
131
+ end
132
+
133
+ def can_write?
134
+ false
135
+ end
136
+ end
137
+ end
138
+