kindergarten 0.1.0 → 0.1.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.
- data/.travis.yml +4 -1
- data/Gemfile +2 -0
- data/TODO.md +3 -1
- data/kindergarten.gemspec +2 -0
- data/lib/kindergarten.rb +9 -0
- data/lib/kindergarten/event.rb +32 -0
- data/lib/kindergarten/exceptions.rb +11 -0
- data/lib/kindergarten/governesses/head_governess.rb +7 -1
- data/lib/kindergarten/orm/active_record.rb +9 -9
- data/lib/kindergarten/perimeter.rb +22 -3
- data/lib/kindergarten/purpose.rb +34 -3
- data/lib/kindergarten/sandbox.rb +61 -8
- data/lib/kindergarten/version.rb +1 -1
- data/spec/kindergarten/perimeter_spec.rb +8 -3
- data/spec/kindergarten/purpose_spec.rb +55 -0
- data/spec/kindergarten/sandbox_spec.rb +91 -3
- data/spec/kindergarten_spec.rb +16 -0
- data/spec/spec_helper.rb +6 -1
- data/spec/support/illegal_module.rb +8 -0
- data/spec/support/puppet_perimeter.rb +5 -4
- data/spec/support/spec_perimeter.rb +27 -1
- metadata +41 -16
data/.travis.yml
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
language: ruby
|
|
2
|
+
before_install:
|
|
3
|
+
- gem install bundler
|
|
4
|
+
|
|
2
5
|
rvm:
|
|
3
6
|
- 1.9.3
|
|
4
7
|
- 1.9.2
|
|
@@ -11,11 +14,11 @@ rvm:
|
|
|
11
14
|
- 1.8.7
|
|
12
15
|
- ree
|
|
13
16
|
|
|
17
|
+
|
|
14
18
|
services: mysql
|
|
15
19
|
before_script:
|
|
16
20
|
- mysql -e 'create database kindergarten_test;'
|
|
17
21
|
|
|
18
22
|
branches:
|
|
19
23
|
only:
|
|
20
|
-
- master
|
|
21
24
|
- develop
|
data/Gemfile
CHANGED
|
@@ -3,11 +3,13 @@ source 'https://rubygems.org'
|
|
|
3
3
|
# for travis, use a real gemfile
|
|
4
4
|
gem "cancan", "~> 1.6.8"
|
|
5
5
|
gem "activesupport", "> 3"
|
|
6
|
+
gem "rufus-json"
|
|
6
7
|
|
|
7
8
|
group :development do
|
|
8
9
|
gem "bundler", "~> 1.2"
|
|
9
10
|
gem "rake"
|
|
10
11
|
gem "rspec", '~> 2.11'
|
|
12
|
+
gem "mocha"
|
|
11
13
|
gem "activerecord", "> 3"
|
|
12
14
|
platforms :jruby do
|
|
13
15
|
gem 'jdbc-mysql'
|
data/TODO.md
CHANGED
data/kindergarten.gemspec
CHANGED
|
@@ -17,9 +17,11 @@ Gem::Specification.new do |gem|
|
|
|
17
17
|
|
|
18
18
|
gem.add_dependency('cancan', ['~> 1.6.8'])
|
|
19
19
|
gem.add_dependency('activesupport', ['> 3'])
|
|
20
|
+
gem.add_dependency('rufus-json')
|
|
20
21
|
|
|
21
22
|
gem.add_development_dependency('rake')
|
|
22
23
|
gem.add_development_dependency('rspec', ['~> 2.11'])
|
|
24
|
+
gem.add_development_dependency('mocha')
|
|
23
25
|
gem.add_development_dependency('activerecord', ['> 3'])
|
|
24
26
|
gem.add_development_dependency('mysql2')
|
|
25
27
|
gem.add_development_dependency('jdbc-mysql')
|
data/lib/kindergarten.rb
CHANGED
|
@@ -4,15 +4,24 @@ require 'active_support/core_ext'
|
|
|
4
4
|
require "kindergarten/version"
|
|
5
5
|
require "kindergarten/sandbox"
|
|
6
6
|
require "kindergarten/purpose"
|
|
7
|
+
require "kindergarten/event"
|
|
7
8
|
require "kindergarten/perimeter"
|
|
8
9
|
require "kindergarten/governesses"
|
|
9
10
|
require "kindergarten/exceptions"
|
|
10
11
|
|
|
11
12
|
module Kindergarten
|
|
12
13
|
class << self
|
|
14
|
+
attr_accessor :warnings
|
|
13
15
|
def sandbox(child)
|
|
14
16
|
Kindergarten::Sandbox.new(child)
|
|
15
17
|
end
|
|
18
|
+
|
|
19
|
+
def warning(msg)
|
|
20
|
+
return if @warnings == false
|
|
21
|
+
return warning("Empty warning message") if msg.nil?
|
|
22
|
+
|
|
23
|
+
warn("WARNING: #{msg}")
|
|
24
|
+
end
|
|
16
25
|
end
|
|
17
26
|
end
|
|
18
27
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'rufus-json/automatic'
|
|
2
|
+
|
|
3
|
+
module Kindergarten
|
|
4
|
+
class Event
|
|
5
|
+
attr_reader :name, :purpose, :payload
|
|
6
|
+
|
|
7
|
+
def self.load(hash)
|
|
8
|
+
if hash.is_a?(String)
|
|
9
|
+
hash = begin
|
|
10
|
+
Rufus::Json.decode(hash)
|
|
11
|
+
rescue => ex
|
|
12
|
+
raise ArgumentError.new("The provided string could not be decoded as JSON")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
hash.symbolize_keys!
|
|
17
|
+
self.new(hash[:name], hash[:purpose], hash[:payload])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def initialize(name, purpose, payload)
|
|
21
|
+
@name = name || raise("An event must have a name")
|
|
22
|
+
@purpose = purpose || raise("An event must have a purpose")
|
|
23
|
+
@payload = payload
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_json
|
|
27
|
+
Rufus::Json.encode(
|
|
28
|
+
:name => @name, :purpose => @purpose, :payload => @payload
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -48,6 +48,17 @@ module Kindergarten
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
class RestrictedMethodError < ArgumentError
|
|
52
|
+
def initialize(perimeter, method)
|
|
53
|
+
@perimeter = perimeter
|
|
54
|
+
@method = method
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def to_s
|
|
58
|
+
"You exposed '#{method}' on the #{perimeter}, but that is a restricted method"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
51
62
|
# Signals bad sandbox method implementation
|
|
52
63
|
class Unguarded < SecurityError; end
|
|
53
64
|
end
|
|
@@ -91,10 +91,16 @@ module Kindergarten
|
|
|
91
91
|
def scrub(attributes, *list)
|
|
92
92
|
list.map!(&:to_sym)
|
|
93
93
|
|
|
94
|
+
if attributes.respond_to?(:symbolize_keys!)
|
|
95
|
+
attributes.symbolize_keys!
|
|
96
|
+
else
|
|
97
|
+
attributes = attributes.symbolize_keys
|
|
98
|
+
end
|
|
99
|
+
|
|
94
100
|
forbidden = Kindergarten::Governesses.forbidden_keys
|
|
95
101
|
|
|
96
102
|
Kindergarten::ScrubbedHash[
|
|
97
|
-
attributes.
|
|
103
|
+
attributes.delete_if do |key,value|
|
|
98
104
|
forbidden.include?(key) || !list.include?(key)
|
|
99
105
|
end
|
|
100
106
|
]
|
|
@@ -3,38 +3,38 @@ module Kindergarten::ORM
|
|
|
3
3
|
def self.included(base)
|
|
4
4
|
base.extend(ClassMethods)
|
|
5
5
|
end
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def update_attributes(hash)
|
|
8
8
|
self.class.check(:update_attributes, hash)
|
|
9
9
|
end
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
module ClassMethods
|
|
12
12
|
def create(*args)
|
|
13
13
|
check(:create, *args)
|
|
14
14
|
super
|
|
15
15
|
end
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
def new(*args)
|
|
18
18
|
check(:new, *args)
|
|
19
19
|
super
|
|
20
20
|
end
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
def check(method, *args)
|
|
23
23
|
required = self.force_rinsed? ?
|
|
24
|
-
Kindergarten::RinsedHash :
|
|
24
|
+
Kindergarten::RinsedHash :
|
|
25
25
|
Kindergarten::ScrubbedHash
|
|
26
26
|
|
|
27
27
|
if args[0].is_a?(Array)
|
|
28
28
|
args.each do |input|
|
|
29
|
-
raise Unscrubbed unless input.is_a?(required)
|
|
29
|
+
raise Unscrubbed unless input.is_a?(required)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
elsif args[0].is_a?(Hash)
|
|
33
33
|
raise Unscrubbed unless args[0].is_a?(required)
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
elsif args.any?
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
Kindergarten.warning "#{self.name}.#{method} called with unkown signature"
|
|
37
|
+
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
end
|
|
@@ -83,9 +83,13 @@ module Kindergarten
|
|
|
83
83
|
@callbacks[purpose][event] ||= []
|
|
84
84
|
@callbacks[purpose][event] << block
|
|
85
85
|
end
|
|
86
|
+
|
|
87
|
+
def subscriptions
|
|
88
|
+
@callbacks ||= {}
|
|
89
|
+
end
|
|
86
90
|
end
|
|
87
91
|
|
|
88
|
-
attr_reader :child, :governess
|
|
92
|
+
attr_reader :child, :governess, :sandbox
|
|
89
93
|
|
|
90
94
|
# Obtain an un-sandboxed instance for testing purposes
|
|
91
95
|
#
|
|
@@ -95,8 +99,14 @@ module Kindergarten
|
|
|
95
99
|
self.new(child, governess)
|
|
96
100
|
end
|
|
97
101
|
|
|
98
|
-
def initialize(
|
|
99
|
-
|
|
102
|
+
def initialize(sandbox, governess)
|
|
103
|
+
if sandbox.is_a? Kindergarten::Sandbox
|
|
104
|
+
@sandbox = sandbox
|
|
105
|
+
@child = sandbox.child
|
|
106
|
+
else
|
|
107
|
+
@child = sandbox
|
|
108
|
+
end
|
|
109
|
+
|
|
100
110
|
@governess = governess
|
|
101
111
|
|
|
102
112
|
unless @governess.nil? || self.class.govern_proc.nil?
|
|
@@ -125,5 +135,14 @@ module Kindergarten
|
|
|
125
135
|
end
|
|
126
136
|
end
|
|
127
137
|
|
|
138
|
+
def fire(event, payload=nil)
|
|
139
|
+
if @sandbox.nil?
|
|
140
|
+
Kindergarten.warning("There is no sandbox, is this a test-perimeter?")
|
|
141
|
+
return
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
@sandbox.purpose[self.class.purpose].fire(event, payload)
|
|
145
|
+
end
|
|
146
|
+
|
|
128
147
|
end
|
|
129
148
|
end
|
data/lib/kindergarten/purpose.rb
CHANGED
|
@@ -3,11 +3,15 @@ module Kindergarten
|
|
|
3
3
|
class Purpose
|
|
4
4
|
attr_reader :name, :methods, :sandbox, :subscriptions
|
|
5
5
|
|
|
6
|
+
RESTRICTED_METHOD_NAMES = [ :_subscribe, :fire, :add_perimeter,
|
|
7
|
+
:initialize,
|
|
8
|
+
]
|
|
9
|
+
|
|
6
10
|
def initialize(name, sandbox)
|
|
7
11
|
@name = name
|
|
8
12
|
@sandbox = sandbox
|
|
9
13
|
@methods = {}
|
|
10
|
-
@subscriptions =
|
|
14
|
+
@subscriptions = {}
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def add_perimeter(perimeter, instance)
|
|
@@ -16,14 +20,41 @@ module Kindergarten
|
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
perimeter.exposed_methods.each do |name|
|
|
19
|
-
if
|
|
20
|
-
|
|
23
|
+
if RESTRICTED_METHOD_NAMES.include?(name)
|
|
24
|
+
raise(
|
|
25
|
+
Kindergarten::Perimeter::RestrictedMethodError.new(perimeter, name)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
elsif @methods.has_key?(name)
|
|
29
|
+
|
|
30
|
+
Kindergarten.warning "overriding already sandboxed method #{@name}.#{name}"
|
|
21
31
|
end
|
|
22
32
|
|
|
23
33
|
@methods[name] = instance
|
|
24
34
|
end
|
|
25
35
|
end
|
|
26
36
|
|
|
37
|
+
def _subscribe(event, &block)
|
|
38
|
+
@subscriptions[event] ||= []
|
|
39
|
+
@subscriptions[event] << block
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def _unsubscribe(event)
|
|
43
|
+
@subscriptions.delete(event)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def fire(event_name, payload=nil)
|
|
47
|
+
event = Kindergarten::Event.new(event_name, self.name, payload)
|
|
48
|
+
|
|
49
|
+
if @subscriptions.has_key?(event_name)
|
|
50
|
+
@subscriptions[event_name].each do |proc|
|
|
51
|
+
proc.call(event, self)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
self.sandbox.broadcast!(event)
|
|
56
|
+
end
|
|
57
|
+
|
|
27
58
|
def method_missing(name, *args, &block)
|
|
28
59
|
super
|
|
29
60
|
|
data/lib/kindergarten/sandbox.rb
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
module Kindergarten
|
|
2
2
|
class Sandbox
|
|
3
|
-
attr_reader :child, :governess, :
|
|
3
|
+
attr_reader :child, :governess, :perimeters, :purpose
|
|
4
4
|
|
|
5
5
|
def initialize(child)
|
|
6
6
|
@child = child
|
|
7
7
|
@governess = Kindergarten::HeadGoverness.new(child)
|
|
8
8
|
|
|
9
|
-
@purpose
|
|
10
|
-
@
|
|
11
|
-
def @perimeter.include?(other)
|
|
12
|
-
(self.collect(&:class) & [ other.class ]).any?
|
|
13
|
-
end
|
|
9
|
+
@purpose = {}
|
|
10
|
+
@perimeters = []
|
|
14
11
|
|
|
15
12
|
@unguarded = false
|
|
16
13
|
end
|
|
17
14
|
|
|
18
15
|
def extend_perimeter(*perimeter_classes)
|
|
19
16
|
perimeter_classes.each do |perimeter_class|
|
|
17
|
+
if @perimeters.collect(&:class).include?(perimeter_class)
|
|
18
|
+
# already have this one
|
|
19
|
+
return
|
|
20
|
+
end
|
|
21
|
+
|
|
20
22
|
# if the perimeter specifies a governess, use that - otherwise appoint
|
|
21
23
|
# the head governess
|
|
22
24
|
child = self.child
|
|
@@ -24,7 +26,7 @@ module Kindergarten
|
|
|
24
26
|
perimeter_class.governess.new(child) :
|
|
25
27
|
self.governess
|
|
26
28
|
|
|
27
|
-
perimeter = perimeter_class.new(
|
|
29
|
+
perimeter = perimeter_class.new(self, governess)
|
|
28
30
|
|
|
29
31
|
raise ArgumentError.new(
|
|
30
32
|
"Module must inherit from Kindergarten::Perimeter"
|
|
@@ -37,7 +39,20 @@ module Kindergarten
|
|
|
37
39
|
self.governess.instance_eval(&perimeter_class.govern_proc)
|
|
38
40
|
end
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
perimeter_class.subscriptions.each do |purpose, events|
|
|
43
|
+
if self.purpose[purpose].nil?
|
|
44
|
+
Kindergarten.warning "#{perimeter_class} has subscriptions on un-loaded purpose :#{purpose}"
|
|
45
|
+
next
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
events.each do |event, blocks|
|
|
49
|
+
blocks.each do |block|
|
|
50
|
+
self.purpose[purpose]._subscribe(event, &block)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
@perimeters << perimeter
|
|
41
56
|
end
|
|
42
57
|
end
|
|
43
58
|
alias_method :load_perimeter, :extend_perimeter
|
|
@@ -73,6 +88,44 @@ module Kindergarten
|
|
|
73
88
|
end
|
|
74
89
|
alias_method :disallowed?, :disallows?
|
|
75
90
|
|
|
91
|
+
def guard(action, target, opts={})
|
|
92
|
+
unless allows?(action, target)
|
|
93
|
+
raise Kindergarten::AccessDenied.new(action, target, opts)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def subscribe(purpose_name, *events, &block)
|
|
98
|
+
unless (purpose = @purpose[purpose_name.to_sym])
|
|
99
|
+
Kindergarten.warning "No such purpose has been loaded: #{purpose_name}"
|
|
100
|
+
return
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
events.each do |event|
|
|
104
|
+
purpose._subscribe(event, &block)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def unsubscribe(purpose_name, *events)
|
|
109
|
+
unless (purpose = @purpose[purpose_name.to_sym])
|
|
110
|
+
Kindergarten.warning "No such purpose has been loaded: #{purpose_name}"
|
|
111
|
+
return
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
events.each do |event|
|
|
115
|
+
purpose._unsubscribe(event)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def broadcast(&block)
|
|
120
|
+
@broadcast = block
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def broadcast!(event)
|
|
124
|
+
return if @broadcast.nil?
|
|
125
|
+
|
|
126
|
+
@broadcast.call(event)
|
|
127
|
+
end
|
|
128
|
+
|
|
76
129
|
# TODO: Find a purpose and call that - move this block to Purpose
|
|
77
130
|
def method_missing(name, *args, &block)
|
|
78
131
|
super
|
data/lib/kindergarten/version.rb
CHANGED
|
@@ -19,8 +19,13 @@ describe Kindergarten::Perimeter do
|
|
|
19
19
|
SpecPerimeter.govern_proc.should be_kind_of(Proc)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
it "should return a governess"
|
|
23
|
-
|
|
22
|
+
it "should return a governess" do
|
|
23
|
+
SpecPerimeter.governess.should_not be_nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should return a purpose" do
|
|
27
|
+
SpecPerimeter.purpose.should_not be_nil
|
|
28
|
+
end
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
describe :instance do
|
|
@@ -56,7 +61,7 @@ describe Kindergarten::Perimeter do
|
|
|
56
61
|
end
|
|
57
62
|
|
|
58
63
|
it "should have the SpecPerimeter" do
|
|
59
|
-
@sandbox.
|
|
64
|
+
@sandbox.perimeters.collect(&:class).should include(SpecPerimeter)
|
|
60
65
|
end
|
|
61
66
|
|
|
62
67
|
it "should fill the governess" do
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
|
|
4
|
+
describe Kindergarten::Purpose do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@sandbox = Kindergarten.sandbox(:child)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should register the methods of a perimeter" do
|
|
10
|
+
purpose = Kindergarten::Purpose.new(:test, @sandbox)
|
|
11
|
+
|
|
12
|
+
expect {
|
|
13
|
+
purpose.add_perimeter(SpecPerimeter, SpecPerimeter.instance(:child))
|
|
14
|
+
}.to change {
|
|
15
|
+
purpose.methods
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should warn on duplicate methods" do
|
|
20
|
+
purpose = Kindergarten::Purpose.new(:test, @sandbox)
|
|
21
|
+
purpose.add_perimeter(SpecPerimeter, SpecPerimeter.instance(:child))
|
|
22
|
+
|
|
23
|
+
prev = $stderr.dup
|
|
24
|
+
$stderr = StringIO.new
|
|
25
|
+
Kindergarten.warnings = true
|
|
26
|
+
|
|
27
|
+
expect {
|
|
28
|
+
purpose.add_perimeter(SpecPerimeter, SpecPerimeter.instance(:child))
|
|
29
|
+
}.to change {
|
|
30
|
+
$stderr.length
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
$stderr = prev
|
|
34
|
+
Kindergarten.warnings = false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should fail on restricted methods" do
|
|
38
|
+
purpose = Kindergarten::Purpose.new(:test, @sandbox)
|
|
39
|
+
expect {
|
|
40
|
+
purpose.add_perimeter(IllegalModule, IllegalModule.instance(:child))
|
|
41
|
+
}.to raise_error(Kindergarten::Perimeter::RestrictedMethodError)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should delegate method execution to the perimeter" do
|
|
45
|
+
purpose = Kindergarten::Purpose.new(:test, @sandbox)
|
|
46
|
+
perimeter = SpecPerimeter.instance(:child, @sandbox.governess)
|
|
47
|
+
purpose.add_perimeter(SpecPerimeter, perimeter)
|
|
48
|
+
|
|
49
|
+
expect {
|
|
50
|
+
purpose.evented
|
|
51
|
+
}.to change {
|
|
52
|
+
perimeter.evented?
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -20,7 +20,7 @@ describe Kindergarten::Sandbox do
|
|
|
20
20
|
|
|
21
21
|
it "should define an empty perimeter" do
|
|
22
22
|
sandbox = Kindergarten::Sandbox.new(:child)
|
|
23
|
-
sandbox.
|
|
23
|
+
sandbox.perimeters.should be_empty
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
it "should provide a extend_perimeter function" do
|
|
@@ -30,7 +30,7 @@ describe Kindergarten::Sandbox do
|
|
|
30
30
|
expect {
|
|
31
31
|
sandbox.extend_perimeter(SpecPerimeter)
|
|
32
32
|
}.to change {
|
|
33
|
-
sandbox.
|
|
33
|
+
sandbox.perimeters.empty?
|
|
34
34
|
}
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -45,9 +45,15 @@ describe Kindergarten::Sandbox do
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
it "should know the rules accross perimeters" do
|
|
48
|
-
puppet = @sandbox.puppets.
|
|
48
|
+
puppet = @sandbox.puppets.grab
|
|
49
49
|
@sandbox.should be_disallowed(:bbq, puppet)
|
|
50
50
|
end
|
|
51
|
+
|
|
52
|
+
it "should guard the entire sandbox" do
|
|
53
|
+
expect {
|
|
54
|
+
@sandbox.guard(:render, :nothing)
|
|
55
|
+
}.to raise_error(Kindergarten::AccessDenied)
|
|
56
|
+
end
|
|
51
57
|
end
|
|
52
58
|
|
|
53
59
|
describe :Loading do
|
|
@@ -66,6 +72,19 @@ describe Kindergarten::Sandbox do
|
|
|
66
72
|
@sandbox.load_module(PurposelessModule)
|
|
67
73
|
}.to raise_error(Kindergarten::Perimeter::NoPurpose, /PurposelessModule does not have a purpose/)
|
|
68
74
|
end
|
|
75
|
+
|
|
76
|
+
it "should take on all subscriptions" do
|
|
77
|
+
Kindergarten::Purpose.stubs(:_subscribe)
|
|
78
|
+
|
|
79
|
+
@sandbox.load_module(PuppetPerimeter)
|
|
80
|
+
purpose = @sandbox.purpose[:puppets]
|
|
81
|
+
purpose.should_not be_nil
|
|
82
|
+
|
|
83
|
+
# when we load the testing module, it subscribes to puppet play
|
|
84
|
+
purpose.expects(:_subscribe)
|
|
85
|
+
|
|
86
|
+
@sandbox.load_module(SpecPerimeter)
|
|
87
|
+
end
|
|
69
88
|
end
|
|
70
89
|
|
|
71
90
|
describe :Purpose do
|
|
@@ -83,4 +102,73 @@ describe Kindergarten::Sandbox do
|
|
|
83
102
|
@sandbox.purpose.should be_kind_of(Hash)
|
|
84
103
|
end
|
|
85
104
|
end
|
|
105
|
+
|
|
106
|
+
describe :Mediation do
|
|
107
|
+
before(:all) do
|
|
108
|
+
Kindergarten.warnings = true
|
|
109
|
+
end
|
|
110
|
+
after(:all) do
|
|
111
|
+
Kindergarten.warnings = false
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
before(:each) do
|
|
115
|
+
@sandbox = Kindergarten::Sandbox.new(:kid)
|
|
116
|
+
@sandbox.load_module(PuppetPerimeter, DiningPerimeter, SpecPerimeter)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe :subscribe do
|
|
120
|
+
it "should subscribe the sandbox to events" do
|
|
121
|
+
evented = false
|
|
122
|
+
@sandbox.subscribe(:testing, :event) do
|
|
123
|
+
evented = true
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
expect {
|
|
127
|
+
@sandbox.testing.fire(:event)
|
|
128
|
+
}.to change { evented }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "should relay events between purposes" do
|
|
132
|
+
expect {
|
|
133
|
+
@sandbox.puppets.play(:dress, @sandbox.puppets.grab)
|
|
134
|
+
}.to change {
|
|
135
|
+
@sandbox.testing.puppet_dressed?
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
describe :unsubscribe do
|
|
141
|
+
it "should unsubscribe the sandbox from events" do
|
|
142
|
+
evented = 0
|
|
143
|
+
@sandbox.subscribe(:testing, :event) do
|
|
144
|
+
evented += 1
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
expect {
|
|
148
|
+
@sandbox.testing.fire(:event)
|
|
149
|
+
}.to change { evented }
|
|
150
|
+
|
|
151
|
+
@sandbox.unsubscribe(:testing, :event)
|
|
152
|
+
|
|
153
|
+
expect {
|
|
154
|
+
@sandbox.testing.fire(:event)
|
|
155
|
+
}.to_not change { evented }
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
describe :Broadcast do
|
|
160
|
+
it "should broadcast events" do
|
|
161
|
+
evented = 0
|
|
162
|
+
|
|
163
|
+
@sandbox.broadcast do |event|
|
|
164
|
+
evented += 1
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
expect {
|
|
168
|
+
@sandbox.testing.fire(:ce_ci_nest_pas_un_event)
|
|
169
|
+
}.to change { evented }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
end
|
|
86
174
|
end
|
data/spec/kindergarten_spec.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
|
+
require 'stringio'
|
|
2
3
|
|
|
3
4
|
describe Kindergarten do
|
|
4
5
|
it "should have a version constant" do
|
|
@@ -9,4 +10,19 @@ describe Kindergarten do
|
|
|
9
10
|
res = Kindergarten.sandbox("string")
|
|
10
11
|
res.should be_kind_of(Kindergarten::Sandbox)
|
|
11
12
|
end
|
|
13
|
+
|
|
14
|
+
it "should have warnings" do
|
|
15
|
+
Kindergarten.warnings = true
|
|
16
|
+
prev = $stderr.dup
|
|
17
|
+
$stderr = StringIO.new
|
|
18
|
+
|
|
19
|
+
expect {
|
|
20
|
+
Kindergarten.warning "see"
|
|
21
|
+
}.to change {
|
|
22
|
+
$stderr.length
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
$stderr = prev
|
|
26
|
+
Kindergarten.warnings = false
|
|
27
|
+
end
|
|
12
28
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
require 'kindergarten'
|
|
2
|
+
require 'mocha_standalone'
|
|
2
3
|
|
|
3
4
|
Dir[File.expand_path( "../support/**/*.rb", __FILE__)].sort.each { |f| require f }
|
|
4
5
|
|
|
5
6
|
RSpec.configure do |config|
|
|
6
7
|
config.tty = true
|
|
7
|
-
|
|
8
|
+
config.mock_with :mocha
|
|
9
|
+
config.before(:suite) do
|
|
10
|
+
# During the suite, let there be no warnings
|
|
11
|
+
Kindergarten.warnings = false
|
|
12
|
+
end
|
|
8
13
|
end
|
|
@@ -9,13 +9,14 @@ class PuppetPerimeter < Kindergarten::Perimeter
|
|
|
9
9
|
cannot [:tear, :bbq], Puppet
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def
|
|
12
|
+
def grab
|
|
13
13
|
guard(:play_with, Puppet.new)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def
|
|
17
|
-
guard(
|
|
16
|
+
def play(action, puppet)
|
|
17
|
+
guard(action, puppet)
|
|
18
|
+
fire(:play, [action, puppet])
|
|
18
19
|
end
|
|
19
20
|
|
|
20
|
-
sandbox :
|
|
21
|
+
sandbox :grab, :play
|
|
21
22
|
end
|
|
@@ -7,6 +7,11 @@ class SpecPerimeter < Kindergarten::Perimeter
|
|
|
7
7
|
can :view, String
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
subscribe :eating, :eat, :evented
|
|
11
|
+
subscribe :puppets, :play, lambda { |event, purpose|
|
|
12
|
+
purpose.sandbox.testing.dress!
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
# should pass and return the child
|
|
11
16
|
def sandboxed
|
|
12
17
|
guard(:view, child)
|
|
@@ -33,5 +38,26 @@ class SpecPerimeter < Kindergarten::Perimeter
|
|
|
33
38
|
return child.reverse
|
|
34
39
|
end
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
# happens on dining.eat event
|
|
42
|
+
def evented
|
|
43
|
+
@evented = true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def evented?
|
|
47
|
+
@evented == true ? true : false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
expose :dress!
|
|
51
|
+
def dress!
|
|
52
|
+
unguarded
|
|
53
|
+
@dressed = true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def puppet_dressed?
|
|
57
|
+
unguarded
|
|
58
|
+
@dressed == true ? true : false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
sandbox :sandboxed, :not_guarded, :guarded, :unsafe, :evented
|
|
62
|
+
expose :puppet_dressed?
|
|
37
63
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kindergarten
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,11 +9,11 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-
|
|
12
|
+
date: 2012-11-27 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: cancan
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &14791540 !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ~>
|
|
@@ -21,10 +21,10 @@ dependencies:
|
|
|
21
21
|
version: 1.6.8
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements: *
|
|
24
|
+
version_requirements: *14791540
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: activesupport
|
|
27
|
-
requirement: &
|
|
27
|
+
requirement: &14790580 !ruby/object:Gem::Requirement
|
|
28
28
|
none: false
|
|
29
29
|
requirements:
|
|
30
30
|
- - ! '>'
|
|
@@ -32,10 +32,21 @@ dependencies:
|
|
|
32
32
|
version: '3'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
|
-
version_requirements: *
|
|
35
|
+
version_requirements: *14790580
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: rufus-json
|
|
38
|
+
requirement: &14789580 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ! '>='
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
type: :runtime
|
|
45
|
+
prerelease: false
|
|
46
|
+
version_requirements: *14789580
|
|
36
47
|
- !ruby/object:Gem::Dependency
|
|
37
48
|
name: rake
|
|
38
|
-
requirement: &
|
|
49
|
+
requirement: &14788540 !ruby/object:Gem::Requirement
|
|
39
50
|
none: false
|
|
40
51
|
requirements:
|
|
41
52
|
- - ! '>='
|
|
@@ -43,10 +54,10 @@ dependencies:
|
|
|
43
54
|
version: '0'
|
|
44
55
|
type: :development
|
|
45
56
|
prerelease: false
|
|
46
|
-
version_requirements: *
|
|
57
|
+
version_requirements: *14788540
|
|
47
58
|
- !ruby/object:Gem::Dependency
|
|
48
59
|
name: rspec
|
|
49
|
-
requirement: &
|
|
60
|
+
requirement: &14787760 !ruby/object:Gem::Requirement
|
|
50
61
|
none: false
|
|
51
62
|
requirements:
|
|
52
63
|
- - ~>
|
|
@@ -54,10 +65,21 @@ dependencies:
|
|
|
54
65
|
version: '2.11'
|
|
55
66
|
type: :development
|
|
56
67
|
prerelease: false
|
|
57
|
-
version_requirements: *
|
|
68
|
+
version_requirements: *14787760
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: mocha
|
|
71
|
+
requirement: &14803080 !ruby/object:Gem::Requirement
|
|
72
|
+
none: false
|
|
73
|
+
requirements:
|
|
74
|
+
- - ! '>='
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '0'
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: *14803080
|
|
58
80
|
- !ruby/object:Gem::Dependency
|
|
59
81
|
name: activerecord
|
|
60
|
-
requirement: &
|
|
82
|
+
requirement: &14802040 !ruby/object:Gem::Requirement
|
|
61
83
|
none: false
|
|
62
84
|
requirements:
|
|
63
85
|
- - ! '>'
|
|
@@ -65,10 +87,10 @@ dependencies:
|
|
|
65
87
|
version: '3'
|
|
66
88
|
type: :development
|
|
67
89
|
prerelease: false
|
|
68
|
-
version_requirements: *
|
|
90
|
+
version_requirements: *14802040
|
|
69
91
|
- !ruby/object:Gem::Dependency
|
|
70
92
|
name: mysql2
|
|
71
|
-
requirement: &
|
|
93
|
+
requirement: &14801140 !ruby/object:Gem::Requirement
|
|
72
94
|
none: false
|
|
73
95
|
requirements:
|
|
74
96
|
- - ! '>='
|
|
@@ -76,10 +98,10 @@ dependencies:
|
|
|
76
98
|
version: '0'
|
|
77
99
|
type: :development
|
|
78
100
|
prerelease: false
|
|
79
|
-
version_requirements: *
|
|
101
|
+
version_requirements: *14801140
|
|
80
102
|
- !ruby/object:Gem::Dependency
|
|
81
103
|
name: jdbc-mysql
|
|
82
|
-
requirement: &
|
|
104
|
+
requirement: &14800340 !ruby/object:Gem::Requirement
|
|
83
105
|
none: false
|
|
84
106
|
requirements:
|
|
85
107
|
- - ! '>='
|
|
@@ -87,7 +109,7 @@ dependencies:
|
|
|
87
109
|
version: '0'
|
|
88
110
|
type: :development
|
|
89
111
|
prerelease: false
|
|
90
|
-
version_requirements: *
|
|
112
|
+
version_requirements: *14800340
|
|
91
113
|
description: A kindergarten with a perimeter, a governess and a sandbox
|
|
92
114
|
email:
|
|
93
115
|
- hartog@organisedminds.com
|
|
@@ -105,6 +127,7 @@ files:
|
|
|
105
127
|
- TODO.md
|
|
106
128
|
- kindergarten.gemspec
|
|
107
129
|
- lib/kindergarten.rb
|
|
130
|
+
- lib/kindergarten/event.rb
|
|
108
131
|
- lib/kindergarten/exceptions.rb
|
|
109
132
|
- lib/kindergarten/governesses.rb
|
|
110
133
|
- lib/kindergarten/governesses/easy_governess.rb
|
|
@@ -118,6 +141,7 @@ files:
|
|
|
118
141
|
- lib/kindergarten/version.rb
|
|
119
142
|
- spec/kindergarten/governess_spec.rb
|
|
120
143
|
- spec/kindergarten/perimeter_spec.rb
|
|
144
|
+
- spec/kindergarten/purpose_spec.rb
|
|
121
145
|
- spec/kindergarten/sandbox_spec.rb
|
|
122
146
|
- spec/kindergarten_spec.rb
|
|
123
147
|
- spec/orm/active_record_spec.rb
|
|
@@ -127,6 +151,7 @@ files:
|
|
|
127
151
|
- spec/support/db/.gitkeep
|
|
128
152
|
- spec/support/dining_perimeter.rb
|
|
129
153
|
- spec/support/drinking_perimeter.rb
|
|
154
|
+
- spec/support/illegal_module.rb
|
|
130
155
|
- spec/support/log/.gitkeep
|
|
131
156
|
- spec/support/methodless_module.rb
|
|
132
157
|
- spec/support/puppet_perimeter.rb
|