chione 0.0.2
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.
- 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
|
+
|