recess 0.0.2 → 0.0.3
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/lib/recess.rb +3 -4
- data/lib/recess/game.rb +109 -0
- data/lib/recess/inside.rb +15 -11
- data/lib/recess/util.rb +14 -0
- data/lib/recess/version.rb +1 -1
- data/recess.gemspec +1 -2
- data/spec/game_spec.rb +144 -0
- data/spec/inside_spec.rb +3 -1
- data/spec/spec_helper.rb +7 -7
- metadata +14 -26
data/lib/recess.rb
CHANGED
data/lib/recess/game.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
module Recess::Game
|
2
|
+
module ClassMethods
|
3
|
+
def recess_list_of_games
|
4
|
+
@game_with ||= []
|
5
|
+
end
|
6
|
+
|
7
|
+
def game_with(what, options = {})
|
8
|
+
clazz_name = what.to_s
|
9
|
+
rules_clazz = Recess::Util.constantize(clazz_name)
|
10
|
+
args = rules_clazz.list.clone
|
11
|
+
args << options
|
12
|
+
send(:inside, clazz_name, *args)
|
13
|
+
recess_list_of_games << clazz_name
|
14
|
+
|
15
|
+
unless method_defined? :recess_rules_game_object_mapping
|
16
|
+
define_method(:recess_rules_game_object_mapping) do |rule|
|
17
|
+
key = rule.to_s
|
18
|
+
@cached_recess_games ||= self.recess_games
|
19
|
+
@recess_rules_game_object_mapping ||= {}
|
20
|
+
|
21
|
+
game_clazz_name = @cached_recess_games[key]
|
22
|
+
# TODO: try again if it's not there? always try?
|
23
|
+
raise "No game implementation of #{key} given." unless game_clazz_name
|
24
|
+
|
25
|
+
game_clazz_name = game_clazz_name.to_s
|
26
|
+
game_clazz = Recess::Util.constantize(game_clazz_name)
|
27
|
+
@recess_rules_game_object_mapping[key] = nil unless @recess_rules_game_object_mapping[key].is_a? game_clazz
|
28
|
+
return @recess_rules_game_object_mapping[key] if @recess_rules_game_object_mapping[key]
|
29
|
+
|
30
|
+
# see if we already have this object
|
31
|
+
obj = nil
|
32
|
+
@cached_recess_games.each do |rule_key, name|
|
33
|
+
if name.to_s == game_clazz_name
|
34
|
+
obj = @recess_rules_game_object_mapping[rule_key]
|
35
|
+
break if obj
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
unless obj
|
40
|
+
data_method = self.class.recess_inside_objects_options[clazz_name][:data]
|
41
|
+
obj = game_clazz.new(self, data_method)
|
42
|
+
end
|
43
|
+
|
44
|
+
@recess_rules_game_object_mapping[key] = obj
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
unless method_defined? :recess_reset_games
|
49
|
+
define_method(:recess_reset_games) do
|
50
|
+
@cached_recess_games = nil
|
51
|
+
@recess_rules_game_object_mapping = nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Rules < Recess::Inside::Base
|
58
|
+
def self.rule(method_name)
|
59
|
+
list << method_name.to_sym
|
60
|
+
|
61
|
+
define_method method_name do |*args|
|
62
|
+
raise "there is no parent object" unless parent_root
|
63
|
+
game_object = parent_root.recess_rules_game_object_mapping(self.class.name.to_s)
|
64
|
+
game_object.send(method_name, *args)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.list
|
69
|
+
@list ||= []
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Base < Recess::Inside::Base
|
74
|
+
def self.rules(clazz)
|
75
|
+
list_of_rules << clazz.to_s
|
76
|
+
end
|
77
|
+
def self.list_of_rules
|
78
|
+
@rules ||= []
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.broken_rules
|
82
|
+
out = []
|
83
|
+
rule_methods_needed.each do |meth|
|
84
|
+
out << meth unless self.method_defined? meth
|
85
|
+
end
|
86
|
+
out
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.follow_rules!
|
90
|
+
missing = self.broken_rules
|
91
|
+
raise "#{self.name} is missing rule method(s): [#{missing.join(", ")}]" unless missing.size == 0
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def self.rule_methods_needed
|
97
|
+
out = []
|
98
|
+
list_of_rules.each do |clazz_name|
|
99
|
+
rules_clazz = Recess::Util.constantize(clazz_name.to_s)
|
100
|
+
out.concat rules_clazz.list
|
101
|
+
end
|
102
|
+
out.uniq
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
Object.send :include, Recess::Game::ClassMethods
|
data/lib/recess/inside.rb
CHANGED
@@ -3,7 +3,7 @@ module Recess::Inside
|
|
3
3
|
def recess_inside_instance_methods(from_base=nil)
|
4
4
|
return [] unless @recess_inside_instance_methods
|
5
5
|
return @recess_inside_instance_methods.keys unless from_base
|
6
|
-
(@recess_inside_base_classes[from_base] || []).uniq
|
6
|
+
(@recess_inside_base_classes[from_base.to_s] || []).uniq
|
7
7
|
end
|
8
8
|
|
9
9
|
def recess_inside_objects_options
|
@@ -12,13 +12,15 @@ module Recess::Inside
|
|
12
12
|
|
13
13
|
def inside(what, *args)
|
14
14
|
options = args.last.is_a?(::Hash) ? args.pop : {}
|
15
|
-
|
16
|
-
|
15
|
+
clazz_name = what.to_s
|
16
|
+
object_clazz = Recess::Util.constantize(clazz_name)
|
17
|
+
|
18
|
+
recess_inside_objects_options[clazz_name] = options
|
17
19
|
|
18
20
|
@recess_inside_instance_methods ||= {}
|
19
21
|
@recess_inside_base_classes ||= {}
|
20
22
|
|
21
|
-
unless @recess_inside_base_classes[
|
23
|
+
unless @recess_inside_base_classes[clazz_name]
|
22
24
|
if object_clazz.respond_to?(:insided)
|
23
25
|
if object_clazz.method(:insided).arity == 1
|
24
26
|
object_clazz.insided(self)
|
@@ -29,18 +31,20 @@ module Recess::Inside
|
|
29
31
|
end
|
30
32
|
|
31
33
|
object_clazz.all_parent_instance_methods.each do |used|
|
32
|
-
@recess_inside_base_classes[
|
33
|
-
@recess_inside_base_classes[
|
34
|
+
@recess_inside_base_classes[clazz_name] ||= []
|
35
|
+
@recess_inside_base_classes[clazz_name] << used
|
34
36
|
|
35
37
|
@recess_inside_instance_methods[used] ||= []
|
36
|
-
@recess_inside_instance_methods[used] <<
|
38
|
+
@recess_inside_instance_methods[used] << clazz_name
|
37
39
|
end
|
38
40
|
|
39
41
|
unless method_defined? :recess_inside_instance_objects
|
40
|
-
define_method(:recess_inside_instance_objects) do |
|
41
|
-
|
42
|
+
define_method(:recess_inside_instance_objects) do |the_name|
|
43
|
+
the_name = the_name.to_s
|
44
|
+
clazz = Recess::Util.constantize(the_name)
|
45
|
+
data_method = self.class.recess_inside_objects_options[the_name][:data]
|
42
46
|
@recess_inside_instance_objects ||= {}
|
43
|
-
@recess_inside_instance_objects[
|
47
|
+
@recess_inside_instance_objects[the_name] ||= clazz.new(self, data_method)
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -57,7 +61,7 @@ module Recess::Inside
|
|
57
61
|
end
|
58
62
|
|
59
63
|
define_method delegated do |*args|
|
60
|
-
recess_inside_instance_objects(
|
64
|
+
recess_inside_instance_objects(clazz_name).send(delegated, *args)
|
61
65
|
end
|
62
66
|
end
|
63
67
|
end
|
data/lib/recess/util.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Recess::Util
|
2
|
+
extend self
|
3
|
+
|
4
|
+
def constantize(camel_cased_word)
|
5
|
+
names = camel_cased_word.split('::')
|
6
|
+
names.shift if names.empty? || names.first.empty?
|
7
|
+
|
8
|
+
constant = Object
|
9
|
+
names.each do |name|
|
10
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
11
|
+
end
|
12
|
+
constant
|
13
|
+
end
|
14
|
+
end
|
data/lib/recess/version.rb
CHANGED
data/recess.gemspec
CHANGED
@@ -18,8 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.add_development_dependency 'rspec'
|
22
|
-
s.add_development_dependency 'mocha', '0.9.8'
|
21
|
+
s.add_development_dependency 'rspec'
|
23
22
|
|
24
23
|
# specify any dependencies here; for example:
|
25
24
|
# s.add_development_dependency "rspec"
|
data/spec/game_spec.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestRules1 < Recess::Game::Rules
|
4
|
+
rule :must_have_one
|
5
|
+
rule :other_one
|
6
|
+
rule "third"
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestRules2 < Recess::Game::Rules
|
10
|
+
rule :extra2
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestGame1 < Recess::Game::Base
|
14
|
+
rules "TestRules2"
|
15
|
+
|
16
|
+
def extra2
|
17
|
+
"yes"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class TestGame2 < Recess::Game::Base
|
22
|
+
rules TestRules2
|
23
|
+
|
24
|
+
def extra2_not_here
|
25
|
+
"no"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class TestGame3 < Recess::Game::Base
|
30
|
+
rules TestRules1
|
31
|
+
rules "TestRules2"
|
32
|
+
|
33
|
+
def must_have_one
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def other_one
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def third
|
42
|
+
"333"
|
43
|
+
end
|
44
|
+
|
45
|
+
def extra2
|
46
|
+
"other"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class TestGame4 < Recess::Game::Base
|
51
|
+
rules TestRules1
|
52
|
+
rules TestRules2
|
53
|
+
|
54
|
+
def must_have_one
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def missing_several
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class TestGameObject1
|
64
|
+
game_with TestRules1
|
65
|
+
game_with TestRules2
|
66
|
+
|
67
|
+
def recess_games
|
68
|
+
{"TestRules2" => "TestGame1", "TestRules1" => TestGame3}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "Rules" do
|
73
|
+
it "should list out the methods" do
|
74
|
+
TestRules1.list.should =~ [:must_have_one, :other_one, :third]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "Games" do
|
79
|
+
describe "following rules" do
|
80
|
+
it "should raise if it doesn't implement all methods" do
|
81
|
+
lambda {
|
82
|
+
TestGame1.follow_rules!
|
83
|
+
}.should_not raise_error
|
84
|
+
|
85
|
+
lambda {
|
86
|
+
TestGame2.follow_rules!
|
87
|
+
}.should raise_error
|
88
|
+
|
89
|
+
lambda {
|
90
|
+
TestGame3.follow_rules!
|
91
|
+
}.should_not raise_error
|
92
|
+
|
93
|
+
lambda {
|
94
|
+
TestGame4.follow_rules!
|
95
|
+
}.should raise_error
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should get a list of rules it doesn't follow" do
|
99
|
+
TestGame1.broken_rules.should == []
|
100
|
+
TestGame2.broken_rules.should =~ [:extra2]
|
101
|
+
TestGame3.broken_rules.should == []
|
102
|
+
TestGame4.broken_rules.should =~ [:other_one, :third, :extra2]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "Containers" do
|
108
|
+
it "should delegate to the implementation" do
|
109
|
+
obj = TestGameObject1.new
|
110
|
+
obj.respond_to?(:extra2).should == true
|
111
|
+
obj.extra2.should == "yes"
|
112
|
+
obj.third.should == "333"
|
113
|
+
|
114
|
+
obj.recess_reset_games
|
115
|
+
obj.stub(:recess_games).and_return({"TestRules2" => TestGame3})
|
116
|
+
obj.extra2.should == "other"
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should raise if it's not there" do
|
120
|
+
obj = TestGameObject1.new
|
121
|
+
obj.stub(:recess_games).and_return({})
|
122
|
+
lambda {
|
123
|
+
obj.extra2
|
124
|
+
}.should raise_error
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should use the same instances if possible" do
|
128
|
+
obj = TestGameObject1.new
|
129
|
+
obj.stub(:recess_games).and_return({"TestRules2" => "TestGame3", "TestRules1" => TestGame3})
|
130
|
+
obj.extra2.should == "other"
|
131
|
+
obj.third.should == "333"
|
132
|
+
|
133
|
+
instance1 = obj.recess_rules_game_object_mapping("TestRules1")
|
134
|
+
instance2 = obj.recess_rules_game_object_mapping("TestRules2")
|
135
|
+
|
136
|
+
instance1.extra2.should == "other"
|
137
|
+
instance1.third.should == "333"
|
138
|
+
instance2.extra2.should == "other"
|
139
|
+
instance2.third.should == "333"
|
140
|
+
|
141
|
+
instance1.object_id.should == instance2.object_id
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
data/spec/inside_spec.rb
CHANGED
@@ -81,7 +81,7 @@ class TestContainer4
|
|
81
81
|
@called_value
|
82
82
|
end
|
83
83
|
|
84
|
-
inside TestInside4, :foo
|
84
|
+
inside "TestInside4", :foo
|
85
85
|
end
|
86
86
|
|
87
87
|
class TestExample1Data
|
@@ -119,6 +119,8 @@ describe "Containers" do
|
|
119
119
|
TestContainer1.recess_inside_instance_methods.should =~ ["foo", "foo="]
|
120
120
|
TestContainer1.recess_inside_instance_methods(TestInside1).should =~ ["foo", "foo="]
|
121
121
|
TestContainer3.recess_inside_instance_methods(TestInside2).should =~ ["foo"]
|
122
|
+
TestContainer1.recess_inside_instance_methods("TestInside1").should =~ ["foo", "foo="]
|
123
|
+
TestContainer3.recess_inside_instance_methods("TestInside2").should =~ ["foo"]
|
122
124
|
end
|
123
125
|
|
124
126
|
it "should allow call through to super" do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
|
4
|
-
Bundler.setup
|
5
|
-
|
6
|
-
require 'spec/autorun'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rspec'
|
7
4
|
|
8
5
|
require 'recess'
|
9
6
|
|
10
|
-
|
11
|
-
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.mock_with :rspec
|
9
|
+
config.filter_run :focus => true
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.order = 'random'
|
12
12
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recess
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brian Leonard
|
@@ -15,7 +15,8 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-10-24 00:00:00 -07:00
|
19
|
+
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: rspec
|
@@ -23,32 +24,14 @@ dependencies:
|
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
25
|
none: false
|
25
26
|
requirements:
|
26
|
-
- - "
|
27
|
+
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
29
|
+
hash: 3
|
29
30
|
segments:
|
30
|
-
- 1
|
31
|
-
- 3
|
32
31
|
- 0
|
33
|
-
version:
|
32
|
+
version: "0"
|
34
33
|
type: :development
|
35
34
|
version_requirements: *id001
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: mocha
|
38
|
-
prerelease: false
|
39
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
-
none: false
|
41
|
-
requirements:
|
42
|
-
- - "="
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
hash: 43
|
45
|
-
segments:
|
46
|
-
- 0
|
47
|
-
- 9
|
48
|
-
- 8
|
49
|
-
version: 0.9.8
|
50
|
-
type: :development
|
51
|
-
version_requirements: *id002
|
52
35
|
description: You know, to break up your classes.
|
53
36
|
email:
|
54
37
|
- brian@bleonard.com
|
@@ -65,14 +48,18 @@ files:
|
|
65
48
|
- README.mdown
|
66
49
|
- Rakefile
|
67
50
|
- lib/recess.rb
|
51
|
+
- lib/recess/game.rb
|
68
52
|
- lib/recess/inside.rb
|
69
53
|
- lib/recess/outside.rb
|
54
|
+
- lib/recess/util.rb
|
70
55
|
- lib/recess/version.rb
|
71
56
|
- recess.gemspec
|
57
|
+
- spec/game_spec.rb
|
72
58
|
- spec/inside_spec.rb
|
73
59
|
- spec/outside_spec.rb
|
74
60
|
- spec/spec_helper.rb
|
75
61
|
- spec/test_spec.rb
|
62
|
+
has_rdoc: true
|
76
63
|
homepage: ""
|
77
64
|
licenses: []
|
78
65
|
|
@@ -102,11 +89,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
89
|
requirements: []
|
103
90
|
|
104
91
|
rubyforge_project: recess
|
105
|
-
rubygems_version: 1.
|
92
|
+
rubygems_version: 1.6.0
|
106
93
|
signing_key:
|
107
94
|
specification_version: 3
|
108
95
|
summary: You know, to break up your classes.
|
109
96
|
test_files:
|
97
|
+
- spec/game_spec.rb
|
110
98
|
- spec/inside_spec.rb
|
111
99
|
- spec/outside_spec.rb
|
112
100
|
- spec/spec_helper.rb
|