chione 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- data/.rdoc_options +22 -0
- data/.simplecov +14 -0
- data/ChangeLog +114 -0
- data/History.rdoc +9 -0
- data/Manifest.txt +27 -0
- data/README.rdoc +96 -0
- data/Rakefile +92 -0
- data/lib/chione.rb +37 -0
- data/lib/chione/aspect.rb +163 -0
- data/lib/chione/assemblage.rb +64 -0
- data/lib/chione/behaviors.rb +31 -0
- data/lib/chione/component.rb +43 -0
- data/lib/chione/entity.rb +80 -0
- data/lib/chione/manager.rb +44 -0
- data/lib/chione/mixins.rb +91 -0
- data/lib/chione/system.rb +69 -0
- data/lib/chione/world.rb +358 -0
- data/spec/chione/aspect_spec.rb +143 -0
- data/spec/chione/assemblage_spec.rb +60 -0
- data/spec/chione/component_spec.rb +54 -0
- data/spec/chione/entity_spec.rb +109 -0
- data/spec/chione/manager_spec.rb +39 -0
- data/spec/chione/mixins_spec.rb +94 -0
- data/spec/chione/system_spec.rb +72 -0
- data/spec/chione/world_spec.rb +451 -0
- data/spec/chione_spec.rb +11 -0
- data/spec/spec_helper.rb +34 -0
- metadata +250 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,143 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'chione/aspect'
|
6
|
+
require 'chione/component'
|
7
|
+
|
8
|
+
|
9
|
+
describe Chione::Aspect do
|
10
|
+
|
11
|
+
let( :location ) do
|
12
|
+
Class.new( Chione::Component ) do
|
13
|
+
field :x, default: 0
|
14
|
+
field :y, default: 0
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
let( :tags ) do
|
19
|
+
Class.new( Chione::Component ) do
|
20
|
+
field :tags, default: []
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let( :color ) do
|
25
|
+
Class.new( Chione::Component ) do
|
26
|
+
field :hue, default: 0
|
27
|
+
field :shade, default: 0
|
28
|
+
field :value, default: 0
|
29
|
+
field :opacity, default: 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
it "doesn't have any default criteria" do
|
35
|
+
aspect = described_class.new
|
36
|
+
expect( aspect.one_of ).to be_empty
|
37
|
+
expect( aspect.all_of ).to be_empty
|
38
|
+
expect( aspect.none_of ).to be_empty
|
39
|
+
expect( aspect ).to be_empty
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
it "can be created with default criteria" do
|
44
|
+
aspect = described_class.with_all_of( tags, location )
|
45
|
+
expect( aspect.one_of ).to be_empty
|
46
|
+
expect( aspect.all_of.size ).to eq( 2 )
|
47
|
+
expect( aspect.all_of ).to include( tags, location )
|
48
|
+
expect( aspect.none_of ).to be_empty
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
it "can make a clone of itself with additional one_of criteria" do
|
53
|
+
aspect = described_class.new
|
54
|
+
clone = aspect.with_one_of( location, tags )
|
55
|
+
expect( clone ).to_not be( aspect )
|
56
|
+
expect( clone.one_of ).to include( location, tags )
|
57
|
+
expect( aspect.one_of ).to be_empty
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
it "can make a clone of itself with additional none_of criteria" do
|
62
|
+
aspect = described_class.with_none_of( location )
|
63
|
+
clone = aspect.with_none_of( tags )
|
64
|
+
expect( clone ).to_not be( aspect )
|
65
|
+
expect( clone.none_of ).to include( location, tags )
|
66
|
+
expect( aspect.none_of.size ).to eq( 1 )
|
67
|
+
expect( aspect.none_of ).to include( location )
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
it "can make a clone of itself with additional all_of criteria" do
|
72
|
+
aspect = described_class.with_all_of( color, location )
|
73
|
+
clone = aspect.with_all_of( tags )
|
74
|
+
expect( clone ).to_not be( aspect )
|
75
|
+
expect( clone.all_of.size ).to eq( 3 )
|
76
|
+
expect( clone.all_of ).to include( location, tags, color )
|
77
|
+
expect( aspect.all_of.size ).to eq( 2 )
|
78
|
+
expect( aspect.all_of ).to include( location, color )
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
it "supports a fluent interface" do
|
83
|
+
aspect = described_class.with_all_of( tags, location ).and_none_of( color )
|
84
|
+
expect( aspect.one_of ).to be_empty
|
85
|
+
expect( aspect.all_of.size ).to eq( 2 )
|
86
|
+
expect( aspect.all_of ).to include( tags, location )
|
87
|
+
expect( aspect.none_of.size ).to eq( 1 )
|
88
|
+
expect( aspect.none_of ).to include( color )
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
it "flattens Arrays passed to ::with_all_of" do
|
93
|
+
aspect = described_class.with_all_of([ tags, location ])
|
94
|
+
|
95
|
+
expect( aspect.all_of.size ).to eq( 2 )
|
96
|
+
expect( aspect.all_of ).to include( tags, location )
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
it "flattens Arrays passed to #with_all_of" do
|
101
|
+
aspect = described_class.new
|
102
|
+
aspect = aspect.with_all_of([ tags, location ])
|
103
|
+
|
104
|
+
expect( aspect.all_of.size ).to eq( 2 )
|
105
|
+
expect( aspect.all_of ).to include( tags, location )
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
it "flattens Arrays passed to ::with_one_of" do
|
110
|
+
aspect = described_class.with_one_of([ tags, location ])
|
111
|
+
|
112
|
+
expect( aspect.one_of.size ).to eq( 2 )
|
113
|
+
expect( aspect.one_of ).to include( tags, location )
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
it "flattens Arrays passed to #with_one_of" do
|
118
|
+
aspect = described_class.new
|
119
|
+
aspect = aspect.with_one_of([ tags, location ])
|
120
|
+
|
121
|
+
expect( aspect.one_of.size ).to eq( 2 )
|
122
|
+
expect( aspect.one_of ).to include( tags, location )
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
it "flattens Arrays passed to ::with_none_of" do
|
127
|
+
aspect = described_class.with_none_of([ tags, location ])
|
128
|
+
|
129
|
+
expect( aspect.none_of.size ).to eq( 2 )
|
130
|
+
expect( aspect.none_of ).to include( tags, location )
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
it "flattens Arrays passed to #with_none_of" do
|
135
|
+
aspect = described_class.new
|
136
|
+
aspect = aspect.with_none_of([ tags, location ])
|
137
|
+
|
138
|
+
expect( aspect.none_of.size ).to eq( 2 )
|
139
|
+
expect( aspect.none_of ).to include( tags, location )
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'chione/assemblage'
|
6
|
+
require 'chione/component'
|
7
|
+
require 'chione/entity'
|
8
|
+
require 'chione/world'
|
9
|
+
|
10
|
+
describe Chione::Assemblage do
|
11
|
+
|
12
|
+
let( :world ) { Chione::World.new }
|
13
|
+
|
14
|
+
let( :location_component ) do
|
15
|
+
Class.new( Chione::Component ) do
|
16
|
+
field :x, default: 0
|
17
|
+
field :y, default: 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
let( :tags_component ) do
|
22
|
+
Class.new( Chione::Component ) do
|
23
|
+
field :tags, default: []
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
it "acts as a factory for entities with pre-set components" do
|
29
|
+
assemblage = Module.new
|
30
|
+
assemblage.extend( described_class )
|
31
|
+
assemblage.add( location_component, x: 10, y: 8 )
|
32
|
+
assemblage.add( tags_component, tags: [:foo, :bar] )
|
33
|
+
|
34
|
+
entity = assemblage.construct_for( world )
|
35
|
+
|
36
|
+
expect( entity ).to be_a( Chione::Entity )
|
37
|
+
expect( entity.world ).to be( world )
|
38
|
+
expect( entity.components ).to include( location_component, tags_component )
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
it "can include other assemblages" do
|
43
|
+
general_assemblage = Module.new
|
44
|
+
general_assemblage.extend( described_class )
|
45
|
+
general_assemblage.add( location_component, x: 10, y: 8 )
|
46
|
+
|
47
|
+
specific_assemblage = Module.new
|
48
|
+
specific_assemblage.extend( described_class )
|
49
|
+
specific_assemblage.send( :include, general_assemblage )
|
50
|
+
specific_assemblage.add( tags_component, tags: [:foo, :bar] )
|
51
|
+
|
52
|
+
entity = specific_assemblage.construct_for( world )
|
53
|
+
|
54
|
+
expect( entity ).to be_a( Chione::Entity )
|
55
|
+
expect( entity.world ).to be( world )
|
56
|
+
expect( entity.components ).to include( location_component, tags_component )
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'chione/component'
|
6
|
+
|
7
|
+
|
8
|
+
describe Chione::Component do
|
9
|
+
|
10
|
+
describe "concrete subclasses" do
|
11
|
+
|
12
|
+
let( :component_subclass ) do
|
13
|
+
Class.new( described_class )
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
it "can declare fields" do
|
18
|
+
component_subclass.field( :x )
|
19
|
+
component_subclass.field( :y )
|
20
|
+
|
21
|
+
instance = component_subclass.new
|
22
|
+
expect( instance ).to respond_to( :x )
|
23
|
+
expect( instance ).to respond_to( :y )
|
24
|
+
|
25
|
+
expect( instance.x ).to be_nil
|
26
|
+
expect( instance.y ).to be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
it "can declare fields with default values" do
|
31
|
+
component_subclass.field( :x, default: 0 )
|
32
|
+
component_subclass.field( :y, default: 18 )
|
33
|
+
|
34
|
+
instance = component_subclass.new
|
35
|
+
expect( instance.x ).to eq( 0 )
|
36
|
+
expect( instance.y ).to eq( 18 )
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it "uses a dup of the default if it's not an immediate object" do
|
41
|
+
component_subclass.field( :things, default: [] )
|
42
|
+
|
43
|
+
instance1 = component_subclass.new
|
44
|
+
instance2 = component_subclass.new
|
45
|
+
|
46
|
+
instance1.things << "a thing"
|
47
|
+
|
48
|
+
expect( instance2.things ).to be_empty
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'chione/entity'
|
6
|
+
require 'chione/component'
|
7
|
+
|
8
|
+
|
9
|
+
describe Chione::Entity do
|
10
|
+
|
11
|
+
let( :world ) { Chione::World.new }
|
12
|
+
|
13
|
+
let( :location_component ) do
|
14
|
+
Class.new( Chione::Component ) do
|
15
|
+
field :x, default: 0
|
16
|
+
field :y, default: 0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let( :tags_component ) do
|
21
|
+
Class.new( Chione::Component ) do
|
22
|
+
field :tags, default: []
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
let( :bounding_box_component ) do
|
27
|
+
Class.new( Chione::Component ) do
|
28
|
+
field :width, default: 1
|
29
|
+
field :height, default: 1
|
30
|
+
field :depth, default: 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
it "knows what world it was created for" do
|
36
|
+
expect( Chione::Entity.new(world).world ).to be( world )
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it "uses the ID it's given in creation" do
|
41
|
+
entity = Chione::Entity.new( world, 'some-other-id' )
|
42
|
+
expect( entity.id ).to eq( 'some-other-id' )
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
it "generates an ID for itself if it isn't given one" do
|
47
|
+
entity = Chione::Entity.new( world )
|
48
|
+
expect( entity.id ).to be_a( String )
|
49
|
+
expect( entity.id.length ).to be >= 8
|
50
|
+
|
51
|
+
expect( Chione::Entity.new(world).id ).to_not eq( entity.id )
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
describe "concrete instance" do
|
56
|
+
|
57
|
+
let( :entity ) { Chione::Entity.new(world) }
|
58
|
+
|
59
|
+
|
60
|
+
it "can have components added to it" do
|
61
|
+
entity.add_component( location_component.new )
|
62
|
+
entity.add_component( tags_component.new )
|
63
|
+
|
64
|
+
expect( entity ).to have_component( location_component )
|
65
|
+
expect( entity ).to have_component( tags_component )
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
it "lets components be fetched from it" do
|
70
|
+
entity.add_component( location_component.new )
|
71
|
+
entity.add_component( tags_component.new )
|
72
|
+
|
73
|
+
expect(
|
74
|
+
entity.get_component( location_component )
|
75
|
+
).to eq( entity.components[location_component] )
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
it "lets one of a list of components be fetched from it" do
|
80
|
+
entity.add_component( location_component.new )
|
81
|
+
entity.add_component( tags_component.new )
|
82
|
+
|
83
|
+
expect(
|
84
|
+
entity.get_component( bounding_box_component, location_component )
|
85
|
+
).to eq( entity.components[location_component] )
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
it "raises a KeyError if it doesn't have a fetched component" do
|
90
|
+
entity.add_component( tags_component.new )
|
91
|
+
|
92
|
+
expect {
|
93
|
+
entity.get_component( location_component )
|
94
|
+
}.to raise_error( KeyError, /#{entity.id} doesn't have/i )
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
it "raises a KeyError if it doesn't have any of several fetched components" do
|
99
|
+
entity.add_component( tags_component.new )
|
100
|
+
|
101
|
+
expect {
|
102
|
+
entity.get_component( location_component, bounding_box_component )
|
103
|
+
}.to raise_error( KeyError, /#{entity.id} doesn't have any of/i )
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'chione/manager'
|
6
|
+
require 'chione/world'
|
7
|
+
|
8
|
+
|
9
|
+
describe Chione::Manager do
|
10
|
+
|
11
|
+
let( :world ) { Chione::World.new }
|
12
|
+
|
13
|
+
|
14
|
+
describe "concrete derivatives" do
|
15
|
+
|
16
|
+
let( :manager_class ) do
|
17
|
+
Class.new( described_class )
|
18
|
+
end
|
19
|
+
|
20
|
+
let( :manager ) { manager_class.new(world) }
|
21
|
+
|
22
|
+
|
23
|
+
it "are required to implement #start" do
|
24
|
+
expect {
|
25
|
+
manager.start
|
26
|
+
}.to raise_error( NotImplementedError, /does not implement/i )
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
it "are required to implement #stop" do
|
31
|
+
expect {
|
32
|
+
manager.stop
|
33
|
+
}.to raise_error( NotImplementedError, /does not implement/i )
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'chione/mixins'
|
6
|
+
|
7
|
+
|
8
|
+
describe Chione, "mixins" do
|
9
|
+
|
10
|
+
describe Chione::MethodUtilities, 'used to extend a class' do
|
11
|
+
|
12
|
+
let!( :extended_class ) do
|
13
|
+
klass = Class.new
|
14
|
+
klass.extend( Chione::MethodUtilities )
|
15
|
+
klass
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can declare a class-level attribute reader" do
|
19
|
+
extended_class.singleton_attr_reader :foo
|
20
|
+
expect( extended_class ).to respond_to( :foo )
|
21
|
+
expect( extended_class ).to_not respond_to( :foo= )
|
22
|
+
expect( extended_class ).to_not respond_to( :foo? )
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can declare a class-level attribute writer" do
|
26
|
+
extended_class.singleton_attr_writer :foo
|
27
|
+
expect( extended_class ).to_not respond_to( :foo )
|
28
|
+
expect( extended_class ).to respond_to( :foo= )
|
29
|
+
expect( extended_class ).to_not respond_to( :foo? )
|
30
|
+
end
|
31
|
+
|
32
|
+
it "can declare a class-level attribute reader and writer" do
|
33
|
+
extended_class.singleton_attr_accessor :foo
|
34
|
+
expect( extended_class ).to respond_to( :foo )
|
35
|
+
expect( extended_class ).to respond_to( :foo= )
|
36
|
+
expect( extended_class ).to_not respond_to( :foo? )
|
37
|
+
end
|
38
|
+
|
39
|
+
it "can declare a class-level alias" do
|
40
|
+
def extended_class.foo
|
41
|
+
return "foo"
|
42
|
+
end
|
43
|
+
extended_class.singleton_method_alias( :bar, :foo )
|
44
|
+
|
45
|
+
expect( extended_class.bar ).to eq( 'foo' )
|
46
|
+
end
|
47
|
+
|
48
|
+
it "can declare an instance attribute predicate method" do
|
49
|
+
extended_class.attr_predicate :foo
|
50
|
+
instance = extended_class.new
|
51
|
+
|
52
|
+
expect( instance ).to_not respond_to( :foo )
|
53
|
+
expect( instance ).to_not respond_to( :foo= )
|
54
|
+
expect( instance ).to respond_to( :foo? )
|
55
|
+
|
56
|
+
expect( instance.foo? ).to be_falsey
|
57
|
+
|
58
|
+
instance.instance_variable_set( :@foo, 1 )
|
59
|
+
expect( instance.foo? ).to be_truthy
|
60
|
+
end
|
61
|
+
|
62
|
+
it "can declare an instance attribute predicate and writer" do
|
63
|
+
extended_class.attr_predicate_accessor :foo
|
64
|
+
instance = extended_class.new
|
65
|
+
|
66
|
+
expect( instance ).to_not respond_to( :foo )
|
67
|
+
expect( instance ).to respond_to( :foo= )
|
68
|
+
expect( instance ).to respond_to( :foo? )
|
69
|
+
|
70
|
+
expect( instance.foo? ).to be_falsey
|
71
|
+
|
72
|
+
instance.foo = 1
|
73
|
+
expect( instance.foo? ).to be_truthy
|
74
|
+
end
|
75
|
+
|
76
|
+
it "can declare a class-level attribute predicate and writer" do
|
77
|
+
extended_class.singleton_predicate_accessor :foo
|
78
|
+
expect( extended_class ).to_not respond_to( :foo )
|
79
|
+
expect( extended_class ).to respond_to( :foo= )
|
80
|
+
expect( extended_class ).to respond_to( :foo? )
|
81
|
+
end
|
82
|
+
|
83
|
+
it "can declare a class-level predicate method" do
|
84
|
+
extended_class.singleton_predicate_reader :foo
|
85
|
+
expect( extended_class ).to_not respond_to( :foo )
|
86
|
+
expect( extended_class ).to_not respond_to( :foo= )
|
87
|
+
expect( extended_class ).to respond_to( :foo? )
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
end
|
94
|
+
|