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