woyo-world 0.0.7 → 0.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2c1c941040eef171a088f6ee54a6416f55eb46ba
4
- data.tar.gz: 881d8203e4a35f0965a191cf47f6706cc18ee8ba
3
+ metadata.gz: 8cbc8a5d94754ea504e7df2e4cee823c172bec1c
4
+ data.tar.gz: 3aa4c6addaf017db4ceddfcbba8c062341883444
5
5
  SHA512:
6
- metadata.gz: eb02560ec28f3cc4c370406424518b5c9246a69c34225903e5a17abde911be52231a9cc1670ffc37036c1da788492b39d78b141a00aa17d1f1776996b748bf84
7
- data.tar.gz: 958c5a2eacdf5be0ef4e3e3a0fd0ba420040bc8842efebdf18d03a5e427cfbf5bfa05eac7eac2fb4b12e84bb653157cc11f8aaee8998a4d6c946c714bea429cd
6
+ metadata.gz: 0170be24f57b4fe0fbbb0bfb576b63ef8e5d5be4e20c86ee81e639728ae003336b4f4e0d035a27795fb5780b15455b6e591bfa260331af0d13b8cc2ad834ba5d
7
+ data.tar.gz: fa95a9aebdd52812b0940d1db8c4f60de33a3212518a5140f09f815018a6b66bec8b345b9c80966146b31ea1e3b1c50af348ed17a906f91773279967dba9717e
@@ -0,0 +1,37 @@
1
+ require_relative 'world_object'
2
+
3
+ module Woyo
4
+
5
+ class Action < WorldObject
6
+
7
+ def initialize_object
8
+ super
9
+ attribute :describe
10
+ exclusion :result
11
+ @proc = proc { nil }
12
+ end
13
+
14
+ def execute
15
+ proc_result = if @proc.arity < 1
16
+ @context.instance_eval &@proc
17
+ else
18
+ @context.instance_exec self, &@proc
19
+ end
20
+ true_members = result.members.select { |member| result[member] }
21
+ true_members = true_members[0] if true_members.count == 1
22
+ true_members = nil if true_members.empty?
23
+ { result: true_members, describe: describe, execution: proc_result }
24
+ end
25
+
26
+ def execution &block
27
+ if block_given?
28
+ @proc = block
29
+ else
30
+ @proc
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
@@ -8,44 +8,61 @@ module Woyo
8
8
 
9
9
  module Attributes
10
10
 
11
+ class AttributesHash < Hash
12
+
13
+ alias_method :names, :keys
14
+ alias_method :set, :[]=
15
+
16
+ attr_reader :listeners
17
+
18
+ def initialize
19
+ @listeners = {}
20
+ end
21
+
22
+ def add_attribute_listener attr, listener
23
+ @listeners[attr] = listener
24
+ end
25
+
26
+ def []= attr, value
27
+ old_value = self[attr]
28
+ super
29
+ if ( listener = @listeners[attr] ) && value != old_value
30
+ listener.notify attr, value
31
+ end
32
+ end
33
+
34
+ end
35
+
11
36
  def attribute *attrs, &block
12
- send :_attributes, attrs, ivn: '@attributes', &block
37
+ attributes *attrs, &block
13
38
  end
14
39
 
15
40
  def attributes *attrs, &block
16
- send :_attributes, attrs, ivn: '@attributes', &block
17
- end
18
-
19
- def _attributes attrs, ivn:, &block
20
- if instance_variable_defined? ivn
21
- ivar = instance_variable_get ivn
22
- else
23
- ivar = instance_variable_set ivn, Woyo::Attributes::AttributesHash.new
24
- end
25
- return ivar if attrs.empty?
41
+ @attributes ||= Woyo::Attributes::AttributesHash.new
42
+ return @attributes if attrs.empty?
26
43
  attrs.each do |attr|
27
44
  case
28
45
  when attr.kind_of?( Hash )
29
46
  attr.each do |attr_sym,default|
30
- define_attr_methods attr_sym, default, ivn: ivn
31
- ivar[attr_sym] = send "#{attr_sym}_default"
47
+ define_attr_methods attr_sym, default
48
+ @attributes[attr_sym] = send "#{attr_sym}_default"
32
49
  end
33
50
  when block
34
- define_attr_methods attr, block, ivn: ivn
35
- ivar[attr] = send "#{attr}_default"
51
+ define_attr_methods attr, block
52
+ @attributes[attr] = send "#{attr}_default"
36
53
  else
37
- unless ivar.include? attr
38
- define_attr_methods attr, ivn: ivn
39
- ivar[attr] = nil
54
+ unless @attributes.include? attr
55
+ define_attr_methods attr
56
+ @attributes[attr] = nil
40
57
  end
41
58
  end
42
59
  end
43
60
  end
44
61
 
45
- def define_attr_methods( attr, default = nil, ivn: )
62
+ def define_attr_methods attr, default = nil
46
63
  define_attr_default attr, default
47
- define_attr_equals attr, ivn: ivn
48
- define_attr attr, ivn: ivn
64
+ define_attr_equals attr
65
+ define_attr attr
49
66
  if default == true || default == false # boolean convenience methods
50
67
  define_attr? attr
51
68
  define_attr! attr
@@ -58,26 +75,31 @@ module Attributes
58
75
  end
59
76
  end
60
77
 
61
- def define_attr_equals( attr, ivn: )
78
+ def define_attr_equals attr
62
79
  define_singleton_method "#{attr}=" do |arg|
63
- ivar = instance_variable_get ivn
64
- ivar[attr] = arg
80
+ @attributes[attr] = arg
65
81
  end
66
82
  end
67
83
 
68
- def define_attr( attr, ivn: )
84
+ def define_attr attr
69
85
  define_singleton_method attr do |arg = nil|
70
- ivar = instance_variable_get ivn
71
- return ivar[attr] = arg unless arg.nil?
86
+ return @attributes[attr] = arg unless arg.nil?
72
87
  case
73
- when ivar[attr].kind_of?( Hash )
74
- true_attribute_match = ivar[attr].detect { |name,value| ivar[name] == true }
75
- return true_attribute_match[1] if true_attribute_match
76
- ivar[attr]
77
- when ivar[attr].respond_to?( :call )
78
- return ivar[attr].arity == 0 ? ivar[attr].call : ivar[attr].call(self)
88
+ when @attributes[attr].kind_of?( Hash )
89
+ truthy_matches = @attributes[attr].collect do |name,value|
90
+ truthy = if @attributes[name].respond_to?( :call )
91
+ @attributes[name].arity == 0 ? @attributes[name].call : @attributes[name].call(self)
92
+ else
93
+ @attributes[name]
94
+ end
95
+ truthy ? value : nil
96
+ end.compact
97
+ truthy_matches = truthy_matches.count == 1 ? truthy_matches[0] : truthy_matches
98
+ return truthy_matches
99
+ when @attributes[attr].respond_to?( :call )
100
+ return @attributes[attr].arity == 0 ? @attributes[attr].call : @attributes[attr].call(self)
79
101
  else
80
- ivar[attr]
102
+ @attributes[attr]
81
103
  end
82
104
  end
83
105
  end
@@ -102,54 +124,6 @@ module Attributes
102
124
  send "#{attr}=", true
103
125
  end
104
126
 
105
- def groups
106
- @groups
107
- end
108
-
109
- def group sym, *attrs
110
- @groups ||= {}
111
- grp = @groups[sym] ? @groups[sym] : ( @groups[sym] = Woyo::Attributes::Group.new attributes )
112
- attributes *attrs
113
- attrs.each do |attr|
114
- if attr.kind_of? Hash
115
- attr.each do |attr_sym,default_value|
116
- grp << attr_sym
117
- end
118
- else
119
- grp << attr
120
- end
121
- end
122
- define_singleton_method sym do
123
- @groups[sym]
124
- end
125
- grp
126
- end
127
-
128
- def exclusions
129
- @exclusions
130
- end
131
-
132
- def exclusion sym, *attrs
133
- @exclusions ||= {}
134
- exc = @exclusions[sym] ? @exclusions[sym] : ( @exclusions[sym] = Woyo::Attributes::Exclusion.new attributes )
135
- attributes *attrs
136
- attrs.each do |attr|
137
- define_attr? attr
138
- define_attr! attr
139
- if attr.kind_of? Hash
140
- attr.each do |attr_sym,default_value|
141
- exc << attr_sym
142
- end
143
- else
144
- exc << attr
145
- end
146
- end
147
- define_singleton_method sym do
148
- @exclusions[sym]
149
- end
150
- exc
151
- end
152
-
153
127
  end
154
128
 
155
129
  end
@@ -1,34 +1,10 @@
1
1
  require 'forwardable'
2
+ require_relative 'attributes'
2
3
 
3
4
  module Woyo
4
5
 
5
6
  module Attributes
6
7
 
7
- class AttributesHash < Hash
8
-
9
- alias_method :names, :keys
10
- alias_method :set, :[]=
11
-
12
- attr_reader :listeners
13
-
14
- def initialize
15
- @listeners = {}
16
- end
17
-
18
- def add_attribute_listener attr, listener
19
- @listeners[attr] = listener
20
- end
21
-
22
- def []= attr, value
23
- old_value = self[attr]
24
- super
25
- if ( listener = @listeners[attr] ) && value != old_value
26
- listener.notify attr, value
27
- end
28
- end
29
-
30
- end
31
-
32
8
  class Group
33
9
 
34
10
  extend Forwardable
@@ -110,6 +86,54 @@ module Attributes
110
86
 
111
87
  end
112
88
 
89
+ def groups
90
+ @groups
91
+ end
92
+
93
+ def group sym, *attrs
94
+ @groups ||= {}
95
+ grp = @groups[sym] ? @groups[sym] : ( @groups[sym] = Woyo::Attributes::Group.new attributes )
96
+ attributes *attrs
97
+ attrs.each do |attr|
98
+ if attr.kind_of? Hash
99
+ attr.each do |attr_sym,default_value|
100
+ grp << attr_sym
101
+ end
102
+ else
103
+ grp << attr
104
+ end
105
+ end
106
+ define_singleton_method sym do
107
+ @groups[sym]
108
+ end
109
+ grp
110
+ end
111
+
112
+ def exclusions
113
+ @exclusions
114
+ end
115
+
116
+ def exclusion sym, *attrs
117
+ @exclusions ||= {}
118
+ exc = @exclusions[sym] ? @exclusions[sym] : ( @exclusions[sym] = Woyo::Attributes::Exclusion.new attributes )
119
+ attributes *attrs
120
+ attrs.each do |attr|
121
+ define_attr? attr
122
+ define_attr! attr
123
+ if attr.kind_of? Hash
124
+ attr.each do |attr_sym,default_value|
125
+ exc << attr_sym
126
+ end
127
+ else
128
+ exc << attr
129
+ end
130
+ end
131
+ define_singleton_method sym do
132
+ @exclusions[sym]
133
+ end
134
+ exc
135
+ end
136
+
113
137
  end
114
138
 
115
139
  end
@@ -1,3 +1,3 @@
1
1
  module Woyo
2
- WORLD_VERSION = "0.0.7"
2
+ WORLD_VERSION = "0.0.8"
3
3
  end
@@ -47,7 +47,6 @@ class Way < WorldObject
47
47
  raise "Symbol required, but #{arg.class} : '#{arg}' given."
48
48
  end
49
49
  end
50
-
51
50
 
52
51
  def go
53
52
  { go: open?, going: self.going }
@@ -1,4 +1,5 @@
1
1
  require_relative 'world_object'
2
+ require_relative 'action'
2
3
  require_relative 'location'
3
4
  require_relative 'way'
4
5
  require_relative 'item'
@@ -1,6 +1,4 @@
1
-
2
1
  require_relative 'attributes'
3
- require_relative 'actions'
4
2
  require_relative 'evaluate'
5
3
 
6
4
  module Woyo
@@ -8,12 +6,13 @@ module Woyo
8
6
  class WorldObject
9
7
 
10
8
  include Attributes
11
- include Actions
12
9
  include Evaluate
13
10
 
14
11
  attr_reader :id, :context
15
12
  attr_accessor :_test
16
13
 
14
+ children :action
15
+
17
16
  def initialize id, context: nil, &block
18
17
  @id = id.to_s.downcase.to_sym
19
18
  @context = context
@@ -219,9 +219,10 @@ describe 'DSL' do
219
219
 
220
220
  head 'Items'
221
221
 
222
- doc 'stuff here' do
223
- pending
224
- end
222
+ doc 'stuff here'
223
+ # do
224
+ # pending
225
+ # end
225
226
 
226
227
  end
227
228
 
@@ -309,17 +310,20 @@ describe 'DSL' do
309
310
  head 'Context'
310
311
  text "Other objects may be referred to in different ways."
311
312
 
312
- doc 'world' do
313
- pending
314
- end
313
+ doc 'world'
314
+ # do
315
+ # pending
316
+ # end
315
317
 
316
- doc 'location' do
317
- pending
318
- end
318
+ doc 'location'
319
+ # do
320
+ # pending
321
+ # end
319
322
 
320
- doc 'context' do
321
- pending
322
- end
323
+ doc 'context'
324
+ # do
325
+ # pending
326
+ # end
323
327
 
324
328
  end
325
329
 
@@ -335,16 +339,124 @@ describe 'DSL' do
335
339
  text "Actions change the state of the world, usually by changing the value of attributes on world objects"
336
340
 
337
341
  doc "making changes" do
338
- text "Actions may be defined for a world object, in this case, an item."
342
+ text "Actions may be defined for a world object, in this case, an item. Actions have an id, and optionally a name and description. The steps an action is to perform is contained within an 'execution' block, which executes in the context of the containing world object."
343
+ code pre: "world.evaluate do",
344
+ code: "location :here do
345
+ item :thing do
346
+ name 'Thing One'
347
+ description 'Rename thing'
348
+ action :rename do
349
+ execution do
350
+ name 'Thing Two'
351
+ end
352
+ end
353
+ end
354
+ end",
355
+ post: "end"
356
+ text "Initially the name is as defined"
357
+ code "location = world.location :here"
358
+ code "thing = location.item :thing" => "world.locations[:here].items[:thing]"
359
+ code "thing.name" => "'Thing One'"
360
+ text "Executing rename action changes the name."
361
+ code "thing.action(:rename).execute"
362
+ code "thing.name" => "'Thing Two'"
363
+ end
364
+
365
+ doc "describing the action " do
366
+ text "When an action is executed it returns information about the action, including a description of the action."
339
367
  code pre: "world.evaluate do",
340
368
  code: "location :here do
341
369
  item :thing do
342
- name 'Thing?'
343
- action :one do
344
- name 'Thing One'
370
+ name 'Thing One'
371
+ action :rename do
372
+ description 'Rename thing'
373
+ describe 'Thing is renamed'
374
+ execution do
375
+ name 'Thing Two'
376
+ end
345
377
  end
346
- action :two do
347
- name 'Thing Two'
378
+ end
379
+ end",
380
+ post: "end"
381
+ text "Initially the name is as defined"
382
+ code "location = world.location :here"
383
+ code "thing = location.item :thing" => "world.locations[:here].items[:thing]"
384
+ code "thing.name" => "'Thing One'"
385
+ text "Executing the rename action returns a result hash."
386
+ code "result = thing.action(:rename).execute" => "{ result: nil, execution: 'Thing Two', describe: 'Thing is renamed' }"
387
+ text "The name was changed as expected"
388
+ code "thing.name" => "'Thing Two'"
389
+ text "The contents of the result hash are useful to an application such as Woyo::Server that interacts with the world."
390
+ text "Action execution may be described with a default text (as in this case), or the value of :result can determine the describing text (as we'll see in the next example)."
391
+ code "result[:describe]" => "'Thing is renamed'"
392
+ text "The actual value returned by the execution block is also provided, this may be any kind of object."
393
+ code "result[:execution]" => "'Thing Two'"
394
+ end
395
+
396
+ doc "one of many descriptions" do
397
+ text "An action may be described for different results. An exclusion group of results ensures that only one description will be chosen. Here possible results are :success and :failure."
398
+ code pre: "world.evaluate do",
399
+ code: "location :here do
400
+ item :thing do
401
+ name 'Thing One'
402
+ action :rename do
403
+ description 'Rename thing'
404
+ exclusion :result, :success, :failure
405
+ describe success: 'Thing is renamed',
406
+ failure: 'Not renamed'
407
+ execution do |this|
408
+ if name == 'Thing One'
409
+ name 'Thing Two'
410
+ this.success!
411
+ else
412
+ this.failure!
413
+ end
414
+ end
415
+ end
416
+ end
417
+ end",
418
+ post: "end"
419
+ text "Initially the name is as defined"
420
+ code "location = world.location :here"
421
+ code "thing = location.item :thing" => "world.locations[:here].items[:thing]"
422
+ code "thing.name" => "'Thing One'"
423
+ text "Executing the rename action once succeeds."
424
+ code "thing.action(:rename).execute" => "{ result: :success, describe: 'Thing is renamed', execution: true }"
425
+ text "The name was changed as expected"
426
+ code "thing.name" => "'Thing Two'"
427
+ text "Executing the rename action again fails."
428
+ code "thing.action(:rename).execute" => "{ result: :failure, describe: 'Not renamed', execution: true }"
429
+ text "The name is unchanged."
430
+ code "thing.name" => "'Thing Two'"
431
+ end
432
+
433
+ doc "some of many descriptions" do
434
+ text "An action may be described for results other than :success and :failure, and may return multiple results and descriptions. This is achieved by specifying a group :result containing expected results."
435
+ code pre: "world.evaluate do",
436
+ code: "location :here do
437
+ item :thing do
438
+ name 'Thing One'
439
+ action :rename do
440
+ description 'Rename thing'
441
+ group :result, :renamed, :special, :same
442
+ describe renamed: 'Thing is renamed',
443
+ special: 'Newly discovered thing',
444
+ same: 'Not renamed'
445
+ execution do |this|
446
+ case
447
+ when name == 'Thing One'
448
+ name 'Thing Two'
449
+ this.renamed = true
450
+ when name == 'Thing Two'
451
+ name 'Thing Three'
452
+ this.renamed = true
453
+ this.special = true
454
+ else
455
+ this.renamed = false
456
+ this.special = false
457
+ this.same = true
458
+ end
459
+ end
348
460
  end
349
461
  end
350
462
  end",
@@ -352,13 +464,16 @@ describe 'DSL' do
352
464
  text "Initially the name is as defined"
353
465
  code "location = world.location :here"
354
466
  code "thing = location.item :thing" => "world.locations[:here].items[:thing]"
355
- code "thing.name" => "'Thing?'"
356
- text "Invoking action 'one', changes the name."
357
- code "thing.one"
358
467
  code "thing.name" => "'Thing One'"
359
- text "Invoking action 'two', changes the name again."
360
- code "thing.two"
468
+ text "Executing the rename action once."
469
+ code "thing.action(:rename).execute" => "{ result: :renamed, describe: 'Thing is renamed', execution: true }"
361
470
  code "thing.name" => "'Thing Two'"
471
+ text "Executing the rename action again."
472
+ code "thing.action(:rename).execute" => "{ result: [ :renamed, :special ], describe: [ 'Thing is renamed', 'Newly discovered thing' ], execution: true }"
473
+ code "thing.name" => "'Thing Three'"
474
+ text "Executing the rename action one more time."
475
+ code "thing.action(:rename).execute" => "{ result: :same, describe: 'Not renamed', execution: true }"
476
+ code "thing.name" => "'Thing Three'"
362
477
  end
363
478
 
364
479
  end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+ require 'woyo/world/action'
3
+
4
+ describe Woyo::Action do
5
+
6
+ let( :action ) { Woyo::Action.new :test }
7
+
8
+ context 'has exclusions' do
9
+
10
+ context ':result' do
11
+
12
+ it 'exists' do
13
+ expect(action.exclusions.names).to include :result
14
+ end
15
+
16
+ it 'has no members' do
17
+ expect(action.result.members).to be_empty
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ context "execution may be defined" do
25
+
26
+ it "as a block" do
27
+ action.execution { :answer }
28
+ expect(action.execution).to be_instance_of Proc
29
+ end
30
+
31
+ end
32
+
33
+ context "may be executed" do
34
+
35
+ it 'by calling #execution directly' do
36
+ action.execution { :answer }
37
+ expect(action.execution.call).to eq :answer
38
+ end
39
+
40
+ it 'calling #execution returns nil by default' do
41
+ expect(action.execution.call).to be_nil
42
+ end
43
+
44
+ context 'by calling #execute wrapper' do
45
+
46
+ context 'with result exclusion' do
47
+
48
+ it 'returns result hash with single values for single truthy result' do
49
+ action.exclusion :result, :success, :failure
50
+ action.execution { |this| this.success! }
51
+ action.describe success: "Succeeded"
52
+ expect(action.execute).to eq( { result: :success, describe: "Succeeded", execution: true } )
53
+ end
54
+
55
+ it 'returns result hash with empty results for empty result exclusion' do
56
+ action.describe "Empty"
57
+ expect(action.execute).to eq( { result: nil, describe: "Empty", execution: nil } )
58
+ end
59
+
60
+ end
61
+
62
+ context 'with result group' do
63
+
64
+ it 'returns result hash with single value for single truthy result' do
65
+ action.group :result, a: false, b: true, c: false
66
+ action.describe a: 'aaa', b: 'bbb', c: 'ccc'
67
+ expect(action.execute).to eq( { result: :b, describe: 'bbb', execution: nil } )
68
+ end
69
+
70
+ it 'returns result hash with multiple values for multiple truthy results' do
71
+ action.group :result, a: true, b: false, c: true
72
+ action.describe a: 'aaa', b: 'bbb', c: 'ccc'
73
+ expect(action.execute).to eq( { result: [ :a, :c ], describe: [ 'aaa', 'ccc' ], execution: nil } )
74
+ end
75
+
76
+ it 'returns result hash with empty results for empty result group' do
77
+ action.describe "Empty"
78
+ expect(action.execute).to eq( { result: nil, describe: "Empty", execution: nil } )
79
+ end
80
+
81
+ it 'returns result hash with empty results for no truthy results' do
82
+ action.group :result, a: false, b: false, c: false
83
+ action.describe "Empty"
84
+ expect(action.execute).to eq( { result: nil, describe: "Empty", execution: nil } )
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
@@ -115,15 +115,13 @@ describe Woyo::Attributes do
115
115
  expect(attr_test.attributes.names).to eq [ :attr1, :attr2, :attr3, :attr4 ]
116
116
  end
117
117
 
118
- it 'with a default value' do
118
+ it 'with a default value (non-hash)' do
119
119
  attr_test = AttrTest.new
120
120
  attr_test.attributes attr_with_array___default: [ 1, 2, 3 ]
121
- attr_test.attributes attr_with_hash____default: { a: 1, b: 2, c: 3 }
122
121
  attr_test.attributes attr_with_number__default: 12345
123
122
  attr_test.attributes attr_with_string__default: "abcde"
124
123
  attr_test.attributes attr_with_boolean_default: true
125
124
  expect(attr_test.attr_with_array___default).to eq [ 1, 2, 3 ]
126
- expect(attr_test.attr_with_hash____default).to eq ( { a: 1, b: 2, c: 3 } )
127
125
  expect(attr_test.attr_with_number__default).to eq 12345
128
126
  expect(attr_test.attr_with_string__default).to eq "abcde"
129
127
  expect(attr_test.attr_with_boolean_default).to eq true
@@ -391,26 +389,33 @@ describe Woyo::Attributes do
391
389
  let(:hat) { AttrTest.new }
392
390
 
393
391
  before :each do
394
- hat.attributes :reaction, :hot, :cold
392
+ hat.attributes :reaction, :hot, :warm, :cool, :cold
395
393
  end
396
394
 
397
395
  it 'accept a hash as value' do
398
- expect { hat.reaction hot: 'Sweat', cold: 'Shiver' }.to_not raise_error
396
+ expect { hat.reaction hot: 'Sweat', warm: 'Relax', cool: 'Huddle', cold: 'Shiver', not_attr: 'Nothing' }.to_not raise_error
399
397
  end
400
398
 
401
- it 'return the value of the first key that evaluates as a true attribute' do
402
- hat.reaction hot: 'Sweat', cold: 'Shiver'
399
+ it 'return a list values of the multiple keys that are truthy attributes' do
400
+ hat.reaction hot: 'Sweat', warm: 'Relax', cool: 'Huddle', cold: 'Shiver'
401
+ expect(hat.reaction).to eq [ ]
403
402
  hat.cold = true
404
- expect(hat.reaction).to eq 'Shiver'
405
- hat.hot = true
406
- expect(hat.reaction).to eq 'Sweat'
403
+ hat.cool = proc { 'truthy' }
404
+ hat.warm = proc { nil } # falsey
405
+ hat.hot = false
406
+ expect(hat.reaction).to eq [ 'Huddle', 'Shiver' ]
407
407
  end
408
408
 
409
- it 'otherwise return the hash' do
410
- hat.reaction hot: 'Sweat', cold: 'Shiver'
411
- hat.cold = false
412
- hat.hot = false
413
- expect(hat.reaction).to eq ( { :hot => 'Sweat', :cold => 'Shiver' } )
409
+ it 'return a single value of a single key that is a truthy attribute' do
410
+ hat.reaction hot: 'Sweat', warm: 'Relax', cool: 'Huddle', cold: 'Shiver'
411
+ expect(hat.reaction).to eq [ ]
412
+ hat.warm = true
413
+ expect(hat.reaction).to eq 'Relax'
414
+ end
415
+
416
+ it 'returns empty list if no keys are truthy attributes' do
417
+ hat.reaction hot: 'Sweat', warm: 'Relax', cool: 'Huddle', cold: 'Shiver'
418
+ expect(hat.reaction).to eq [ ]
414
419
  end
415
420
 
416
421
  end
@@ -42,5 +42,26 @@ describe Woyo::Item do
42
42
 
43
43
  end
44
44
 
45
+ context 'actions' do
46
+
47
+ let( :item ) do
48
+ item = Woyo::Item.new :item do
49
+ action( :action1 ) { :empty }
50
+ action( :action2 ) { :empty }
51
+ end
52
+ end
53
+
54
+ it 'are listed' do
55
+ expect(item.actions.count).to eq 2
56
+ expect(item.actions.keys).to eq [ :action1, :action2 ]
57
+ end
58
+
59
+ it 'are accessible' do
60
+ expect(action = item.actions[:action1]).to be_instance_of Woyo::Action
61
+ expect(action.id).to eq :action1
62
+ end
63
+
64
+ end
65
+
45
66
  end
46
67
 
@@ -62,10 +62,12 @@ describe Woyo::WorldObject do
62
62
  it 'actions' do
63
63
  wo = Woyo::WorldObject.new :thing do
64
64
  action :time do
65
- Time.now
65
+ execution do
66
+ Time.now
67
+ end
66
68
  end
67
69
  end
68
- expect(wo.time).to be < Time.now
70
+ expect(wo.action(:time).execution.call).to be < Time.now
69
71
  end
70
72
 
71
73
  end
data/todo.txt CHANGED
@@ -1,40 +1,24 @@
1
1
 
2
- world object features...
3
-
4
- # world
5
-
2
+ World featutes...
3
+
4
+ # actions
5
+
6
+ action.execute #=> {
7
+ result: :symbol, # from result exclusion
8
+ describe: 'text' # first (only) matching symbol
9
+ execution: return_value_from_execution_block
10
+ }
11
+
12
+ action.execute #=> {
13
+ result: [ :symbol1, :symbol2, :symbol3 ] # from result group
14
+ describe: [ 'text1', 'text2', 'text3' ] # all true/truthy members
15
+ execution: return_value_from_execution_block
16
+ }
17
+
6
18
  # attributes
7
19
 
8
-
9
- default procs will be called upon access, not at initialization
10
- this will fix the problem of WorldObject#id being nil when Attributes is prepended and Attributes#initialize is run first
11
-
12
- boolean attributes
13
-
14
- ok detected by class level definition boolean default value
15
-
16
- attribute open: true
17
- attribute dark: false
18
-
19
- ok after defintion, set boolean attribute values...
20
-
21
- open = true
22
- open true
23
- open! # ... open true
24
-
25
- ok query boolean attribute values... ?
26
-
27
- dark
28
- dark? # ... dark ? true : false
29
- is? :dark # ... def is? attr ; attributes[attr] ? true : false ; end
30
-
31
- ok additional class level define (and detect?) boolean attribute values...
32
-
33
- is :open
34
- is :dark
35
- is :warm, :bright
36
-
37
- group...
20
+ attribute returns whole attribute hash
21
+ attribute.render returns array of values with truthy keys
38
22
 
39
23
  group weapons: [ :sword, :knife, :rock, :fists ] # hash - key will be group name, value an array of symbols for members
40
24
  group :weapons, [ :sword, :knife, :rock, :fists ] # symbol will be group name, array of symbols for members
@@ -43,45 +27,11 @@ ok group :weapons, :sword, :knife, :rock, :fists # symbols, first will b
43
27
  group stats: [ speed: 10, charisma: 20, strength: 30 ] # defaults like attributes (these are attributes)
44
28
  ok group :stats, speed: 10, charisma: 20, strength: 30 # ditto
45
29
 
46
- ok group is hash-like
47
- alias :names, :keys
48
-
49
- world_object.weapons.names #=> weapons.keys
50
- world_object.weapons.values #=> weapons.values
51
-
52
- ok group is not an enum, it has no value itself
53
- ok attribute methods for members in parent
54
-
55
- world_object.sword
56
- world_object.knife
57
-
58
- no is group a namespace ? - optional ... attribute methods in group
59
-
60
- world_object.weapons.sword
61
- world_object.weapons.knife
62
-
63
- ok access attributes via group hash
64
-
65
- world_object.weapons[:sword] #=> rusty_sword
66
- world_object.weapons[:sword] = sharp_sword
67
-
68
- ok exclusive group (booleans)...
69
-
70
- ok exclusive_group passable: , :open, :close
71
- exclusive_group light: [ :dark, :dim, :bright ]
72
- exclusive_group temperature: [ :cold, :cool, :warm, :hot ]
73
-
74
- ok same as regular group +...
75
-
76
- ok first member will be true, the rest false
77
- ok additional convenience methods for members...
78
-
79
- world_object.open?
80
- world_object.close?
81
- world_object.open!
82
- world_object.close!
30
+ ok exclusion passable: , :open, :close
31
+ exclusion light: [ :dark, :dim, :bright ]
32
+ exclusion temperature: [ :cold, :cool, :warm, :hot ]
83
33
 
84
- # descriptions
34
+ # descriptions (an attribute)
85
35
 
86
36
  displayed everytime a location is visited...
87
37
 
@@ -136,18 +86,8 @@ ok additional convenience methods for members...
136
86
 
137
87
  # location
138
88
 
139
- locations do NOT contain locations
140
- locations are a graph, linked by ways
141
-
142
- location :here do
143
- name 'Home'
144
- description 'Cosy'
145
- end
146
-
147
89
  location :here, name: 'Home', description: 'cosy'
148
90
 
149
- mass assignment...
150
-
151
91
  locations do
152
92
  home name: 'Home', description: 'Cosy'
153
93
  yard name: 'Garden', description: 'Green'
@@ -156,39 +96,8 @@ ok additional convenience methods for members...
156
96
 
157
97
  # way
158
98
 
159
- a way leads one-way to a location
160
-
161
- way :out do
162
- name 'Door'
163
- description 'Big strong'
164
- to :garden
165
- end
166
-
167
- way can describe being open closed
168
-
169
- way :out do
170
- name 'Door'
171
- to :garden
172
- description 'Wooden door'
173
- description :open => 'An open wooden door leading to sunlit garden',
174
- :closed => 'A closed solid wooden door'
175
- end
176
-
177
- way can describe going (open) or not (closed)
178
-
179
- way :out do
180
- name 'Door'
181
- to :garden
182
- go :open => 'Stepping into the warm sunlight',
183
- :closed => 'The solid wooden door remains stubbornly closed'
184
- end
185
-
186
99
  way :door, to: :other_location, description: 'Big'
187
100
 
188
- is openable, default open
189
-
190
- mass assignment...
191
-
192
101
  ways do
193
102
  east to: :china, name: 'slow boat'
194
103
  west to: :wild_west, name: 'fast horse'
@@ -196,17 +105,13 @@ ok additional convenience methods for members...
196
105
  down to: :pit, name: 'hole'
197
106
  end
198
107
 
199
- standard ways map to directions and movements ?
200
- - north,south,east,west,up,down,forward,back,left,right
108
+ absolute directions
109
+ - north, south, east, west, high, low
201
110
 
202
- # items
203
-
204
- items may be in a location
111
+ relative directions
112
+ - forward, back, left, right, up, down
205
113
 
206
- item :id do
207
- name 'Thing'
208
- description 'Useful object'
209
- end
114
+ # items
210
115
 
211
116
  item :id, name: 'Thing', description: "...", detail: "..."
212
117
 
@@ -223,14 +128,6 @@ ok additional convenience methods for members...
223
128
  longer description when examined
224
129
  detail "....."
225
130
 
226
- have attributes
227
-
228
- attributes :small, :light
229
-
230
- may know their location ?
231
-
232
- if item.location == :home
233
-
234
131
  may know their relation to other items ?
235
132
 
236
133
  if item.contains? :water
@@ -248,8 +145,6 @@ ok additional convenience methods for members...
248
145
 
249
146
  end
250
147
 
251
- # code for ... triggers, events, handlers, conditions, etc...
252
-
253
148
  # can locations, items be subclassed in DSL ?
254
149
 
255
150
  class Vase < Item
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: woyo-world
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerard Fowley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-09 00:00:00.000000000 Z
11
+ date: 2014-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,7 +81,7 @@ files:
81
81
  - README.md
82
82
  - Rakefile
83
83
  - lib/woyo/world.rb
84
- - lib/woyo/world/actions.rb
84
+ - lib/woyo/world/action.rb
85
85
  - lib/woyo/world/attributes.rb
86
86
  - lib/woyo/world/character.rb
87
87
  - lib/woyo/world/evaluate.rb
@@ -97,7 +97,7 @@ files:
97
97
  - spec/spec_doc_formatter.rb
98
98
  - spec/spec_helper.rb
99
99
  - spec/woyo/dsl/dsl_spec.rb
100
- - spec/woyo/world/actions_spec.rb
100
+ - spec/woyo/world/action_spec.rb
101
101
  - spec/woyo/world/attributes_spec.rb
102
102
  - spec/woyo/world/character_spec.rb
103
103
  - spec/woyo/world/evaluate_spec.rb
@@ -139,7 +139,7 @@ test_files:
139
139
  - spec/spec_doc_formatter.rb
140
140
  - spec/spec_helper.rb
141
141
  - spec/woyo/dsl/dsl_spec.rb
142
- - spec/woyo/world/actions_spec.rb
142
+ - spec/woyo/world/action_spec.rb
143
143
  - spec/woyo/world/attributes_spec.rb
144
144
  - spec/woyo/world/character_spec.rb
145
145
  - spec/woyo/world/evaluate_spec.rb
@@ -1,24 +0,0 @@
1
- require_relative 'attributes'
2
-
3
- module Woyo
4
-
5
- module Actions
6
-
7
- include Attributes
8
-
9
- def action *acts, &block
10
- send :_attributes, acts, ivn: '@actions', &block
11
- end
12
-
13
- def actions *acts, &block
14
- send :_attributes, acts, ivn: '@actions', &block
15
- end
16
-
17
- def do act
18
- send act
19
- end
20
-
21
- end
22
-
23
- end
24
-
@@ -1,71 +0,0 @@
1
- require 'spec_helper'
2
- require 'woyo/world/actions'
3
-
4
- describe Woyo::Actions do
5
-
6
- context "may be listed" do
7
-
8
- let( :at ) { class ActionTest ; include Woyo::Actions ; end.new }
9
-
10
- it "intially empty" do
11
- expect(at.actions).to be_instance_of Woyo::Attributes::AttributesHash
12
- expect(at.actions).to be_empty
13
- end
14
-
15
- it "single action" do
16
- at.action( :act1 ) { Time.now }
17
- expect(at.actions.count).to eq 1
18
- expect(at.actions[:act1]). to be_instance_of Proc
19
- end
20
-
21
- it "multiple actions" do
22
- at.action( :act1 ) { Time.now }
23
- at.action( :act2 ) { Time.now }
24
- expect(at.actions.count).to eq 2
25
- expect(at.actions[:act2]). to be_instance_of Proc
26
- end
27
-
28
- end
29
-
30
- context "may be defined" do
31
-
32
- let( :at ) { class ActionTest ; include Woyo::Actions ; end.new }
33
-
34
- it "via a block" do
35
- at.action( :sum ) { 1 + 2 }
36
- expect(at.actions).to include :sum
37
- expect(at.actions[:sum]).to be_instance_of Proc
38
- end
39
-
40
- it "via a proc" do
41
- at.action sum: proc { 1 + 2 }
42
- expect(at.actions).to include :sum
43
- expect(at.actions[:sum]).to be_instance_of Proc
44
- end
45
-
46
- it "via a lambda" do
47
- at.action sum: lambda { |this| 1 + 2 }
48
- expect(at.actions).to include :sum
49
- expect(at.actions[:sum]).to be_instance_of Proc
50
- end
51
-
52
- end
53
-
54
- context "may be invoked" do
55
-
56
- let( :at ) { class ActionTest ; include Woyo::Actions ; end.new }
57
-
58
- it "by name" do
59
- at.action( :sum ) { 1 + 2 }
60
- expect(at.sum).to eq 3
61
- end
62
-
63
- it "via #do :action" do
64
- at.action( :sum ) { 1 + 2 }
65
- expect(at.do :sum).to eq 3
66
- end
67
-
68
- end
69
-
70
- end
71
-