Discussion:
Class that opens and adds variables to instances of another class?
Leam Hall
2018-07-19 09:58:34 UTC
Permalink
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.

Haven't quite figured it out yet, thoughts?

Thanks!

Leam

Here's the error:
###
Traceback (most recent call last):
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
#<Person:0x0000562e9a870978 @data={:name=>"Al"}> (NoMethodError)
###


Code:
###
1 class Person
2 def initialize(data)
3 @data = data
4 end
5 def name
6 @data[:name] || "Fred"
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
16 @person = data[:person]
17 assign_role(data[:role])
18 end
19 def assign_role(role)
20 @person.role = role
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name
30 #al.role = "Cadet Sergeant"
###

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Robert Klemme
2018-07-19 10:09:28 UTC
Permalink
Post by Leam Hall
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name
30 #al.role = "Cadet Sergeant"
###
I would model this differently: a Person has many Roles. A Role does
not record all the persons it is assigned to. Rather, if there is
logic to be executed in the Role a Person is passed in (incomplete
example):

class Person
attr_accessor :roles

def initialize(data)
@data = data
@roles = []
end

def add_role(r)
@roles.include?(r) or @roles << r
self
end
end

class Role
def assign(person)
person.add_role(self)
end

def jump(person)
raise "Not a valid combination #{self} - #{person}" unless
person.roles.include?(self)
puts "#{person.name} jumps #{person.strength * 5}m high!"

end
end

My initial reaction to the word "decorator" was to use SimpleDelegator
but that does not work well for multiple roles which can be added and
removed.

Kind regards

robert
--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Paul Martensen
2018-07-19 10:10:15 UTC
Permalink
Hey!

I think the problem is that

class Role
  class Person
  end
end

Defines a new constant Role::Person which is different to just Person.

If you want to define stuff like this you don't have to reopen the class
to give it new accessors.

class Role
  ::Person.attr_accessor :role
  ...
end

Would work as well. Note that `::Person` makes sure to get the
top-level-namespace Person and not anything else.

Cheers,
Paul
Post by Leam Hall
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes
it. The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
    3: from test_decorator.rb:28:in `<main>'
    2: from test_decorator.rb:28:in `new'
    1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
  1 class Person
  2   def initialize(data)
  4   end
  5   def name
  7   end
  8 end
  9
 10 class Role
 11   class Person
 12     attr_accessor :role
 13   end
 14
 15   def initialize(data)
 17     assign_role(data[:role])
 18   end
 19   def assign_role(role)
 21   end
 22 end
 23
 24 data = {:name => 'Al'}
 25
 26 al = Person.new(data)
 27 role_data = {:person => al, :role => 'Cadet'}
 28 Role.new(role_data)
 29 puts al.name
 30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-b
Andy Jones
2018-07-19 10:12:52 UTC
Permalink
You have to ask yourself: composition or mixin? The easiest way is with a mixin, but it has limitations.

~~~~
module Engineer
def can_do_engines?; true; end
end

class Person
def initialize(name); @name = name; end
end

p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~

Note that you decorate an object --- not a class. If you want to add to the functionality of every instance of a class, I'm not sure that counts as Decorator pattern?

If you want to do it with Composition, instead, have a look at the Ruby documentation for Forwardable. (Sorry this is a bit rushed; chaotic today...)

I think that this might be the article that originally clued me into Decorator? Not sure: https://robots.thoughtbot.com/evaluating-alternative-decorator-implementations-in


-----Original Message-----
From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org] On Behalf Of Leam Hall
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?

I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.

Haven't quite figured it out yet, thoughts?

Thanks!

Leam

Here's the error:
###
Traceback (most recent call last):
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
#<Person:0x0000562e9a870978 @data={:name=>"Al"}> (NoMethodError)
###


Code:
###
1 class Person
2 def initialize(data)
3 @data = data
4 end
5 def name
6 @data[:name] || "Fred"
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
16 @person = data[:person]
17 assign_role(data[:role])
18 end
19 def assign_role(role)
20 @person.role = role
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name
30 #al.role = "Cadet Sergeant"
###

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
leam hall
2018-07-19 12:56:44 UTC
Permalink
Hmm..good question. This stems from my Traveller stuff and the game I'm
writing, which have two different uses for the Person class. Here's the
logic:

1. Every instance of Person
Has a name, gender, and UPP. (character stats)
Can be stored in a language agnostic manner (using JSON)

2. CharacterCreation adds to an instance of Person
Adds physical description, personality

3. Careers add to the instance of person
Skills, rank, notes, money, "stuff"
A character can go through multiple careers.

4. FreeTrader (the game) uses a limited subset of the Person + Additional
stuff.
Ship position(role),
Game uses JSON
Uses Careers, might use CharacterCreation.

5. CharacterData (the database) stores as much information about each
character as possible.
Planning to use Hanami/Sinatra? and a MongoDB backend.
Used to track details of characters for games and books I'm writing.

FreeTrader and CharacterData are separate projects but I want to build from
the same Person base and extend from there. That's why the instance of a
Person might have some attributes and not others.

Leam
Post by Andy Jones
You have to ask yourself: composition or mixin? The easiest way is with a
mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to add to
the functionality of every instance of a class, I'm not sure that counts as
Decorator pattern?
If you want to do it with Composition, instead, have a look at the Ruby
documentation for Forwardable. (Sorry this is a bit rushed; chaotic
today...)
I think that this might be the article that originally clued me into
Decorator? Not sure: https://robots.thoughtbot.com/evaluating-alternative-
decorator-implementations-in
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<
http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data
protection regulations. Please refer to our website to view the ways in
which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-19 13:22:39 UTC
Permalink
Well, first, it seems as if you might find it easier to keep the classes for character creation and the actual game somewhat different. Have the game read the JSON into a separate “model” class that keeps it away from the complexities of character creation, and just lets it deal with the resulting character? I don’t know.

Second, it seems to me that all your characters want to partake in all your addon functionality. The use case for Decorator Pattern is rather different. It’s popular in game design, but not usually used in that way, but rather like this:


flora = Character.new(“Flora the elven druid”)
flora.exend Elf
flora.exend Druid

varian = Character.new(“Varian the dwarven undead druid”)
varian.extend Dwarf
varian.extend Undead
varian.extend Druid


(Apologies if the formatting is odd, Outlook is playing Silly Devils)

If I understand correctly, you might want to go to what Smalltalk used to call “Method Classes” – where you farm off some of your functionality to a helper class that does a job, returns a result, and then never gets called again. It seems like your CharacterCreation might best be that sort of class. But I don’t know it well enough to say for sure.

class Person
def initialize(name, strength)
@name, @strength = name, strength
@foo = ValueOfFooFigurerOuter.new(strength).go
end
end

In the above example, the Person class doesn’t have to care how @foo is calculated. A helper class does that for it.

Hope that helps


From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org] On Behalf Of leam hall
Sent: 19 July 2018 13:57
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?

Hmm..good question. This stems from my Traveller stuff and the game I'm writing, which have two different uses for the Person class. Here's the logic:

1. Every instance of Person
Has a name, gender, and UPP. (character stats)
Can be stored in a language agnostic manner (using JSON)

2. CharacterCreation adds to an instance of Person
Adds physical description, personality

3. Careers add to the instance of person
Skills, rank, notes, money, "stuff"
A character can go through multiple careers.

4. FreeTrader (the game) uses a limited subset of the Person + Additional stuff.
Ship position(role),
Game uses JSON
Uses Careers, might use CharacterCreation.

5. CharacterData (the database) stores as much information about each character as possible.
Planning to use Hanami/Sinatra? and a MongoDB backend.
Used to track details of characters for games and books I'm writing.

FreeTrader and CharacterData are separate projects but I want to build from the same Person base and extend from there. That's why the instance of a Person might have some attributes and not others.

Leam

On Thu, Jul 19, 2018 at 6:12 AM, Andy Jones <***@jameshall.co.uk<mailto:***@jameshall.co.uk>> wrote:
You have to ask yourself: composition or mixin? The easiest way is with a mixin, but it has limitations.

~~~~
module Engineer
def can_do_engines?; true; end
end

class Person
def initialize(name); @name = name; end
end

p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~

Note that you decorate an object --- not a class. If you want to add to the functionality of every instance of a class, I'm not sure that counts as Decorator pattern?

If you want to do it with Composition, instead, have a look at the Ruby documentation for Forwardable. (Sorry this is a bit rushed; chaotic today...)

I think that this might be the article that originally clued me into Decorator? Not sure: https://robots.thoughtbot.com/evaluating-alternative-decorator-implementations-in


-----Original Message-----
From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org<mailto:ruby-talk-***@ruby-lang.org>] On Behalf Of Leam Hall
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?

I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.

Haven't quite figured it out yet, thoughts?

Thanks!

Leam

Here's the error:
###
Traceback (most recent call last):
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
#<Person:0x0000562e9a870978 @data={:name=>"Al"}> (NoMethodError)
###


Code:
###
1 class Person
2 def initialize(data)
3 @data = data
4 end
5 def name
6 @data[:name] || "Fred"
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
16 @person = data[:person]
17 assign_role(data[:role])
18 end
19 def assign_role(role)
20 @person.role = role
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name<http://al.name>
30 #al.role = "Cadet Sergeant"
###

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org<mailto:ruby-talk-***@ruby-lang.org>?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org<mailto:ruby-talk-***@ruby-lang.org>?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>



Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
leam hall
2018-07-19 13:28:58 UTC
Permalink
Hah! I may need a Smalltalk primer, I keep seeing references to it.

Yes, I think your last example is closer to the need and a Decorator might
not be what I'm looking for. The simple explination is:

al = Person.new
Something_That_Changes_Character.new(al)
Something_Else_That_Also_Changes_Character.new(al)

In each case "al" has several attributes modified or added. The "al" passed
to the second Something carries the modifications from the first.

Leam
Post by Andy Jones
Well, first, it seems as if you might find it easier to keep the classes
for character creation and the actual game somewhat different. Have the
game read the JSON into a separate “model” class that keeps it away from
the complexities of character creation, and just lets it deal with the
resulting character? I don’t know.
Second, it seems to me that all your characters want to partake in all
your addon functionality. The use case for Decorator Pattern is rather
different. It’s popular in game design, but not usually used in that way,
flora = Character.new(“Flora the elven druid”)
flora.exend Elf
flora.exend Druid
varian = Character.new(“Varian the dwarven undead druid”)
varian.extend Dwarf
varian.extend Undead
varian.extend Druid
(Apologies if the formatting is odd, Outlook is playing Silly Devils)
If I understand correctly, you might want to go to what Smalltalk used to
call “Method Classes” – where you farm off some of your functionality to a
helper class that does a job, returns a result, and then never gets called
again. It seems like your CharacterCreation might best be that sort of
class. But I don’t know it well enough to say for sure.
class Person
def initialize(name, strength)
@name, @strength = name, strength
@foo = ValueOfFooFigurerOuter.new(strength).go
end
end
calculated. A helper class does that for it.
Hope that helps

hall
*Sent:* 19 July 2018 13:57
*To:* Ruby users
*Subject:* Re: Class that opens and adds variables to instances of
another class?
Hmm..good question. This stems from my Traveller stuff and the game I'm
writing, which have two different uses for the Person class. Here's the
1. Every instance of Person
Has a name, gender, and UPP. (character stats)
Can be stored in a language agnostic manner (using JSON)
2. CharacterCreation adds to an instance of Person
Adds physical description, personality
3. Careers add to the instance of person
Skills, rank, notes, money, "stuff"
A character can go through multiple careers.
4. FreeTrader (the game) uses a limited subset of the Person + Additional stuff.
Ship position(role),
Game uses JSON
Uses Careers, might use CharacterCreation.
5. CharacterData (the database) stores as much information about each
character as possible.
Planning to use Hanami/Sinatra? and a MongoDB backend.
Used to track details of characters for games and books I'm writing.
FreeTrader and CharacterData are separate projects but I want to build
from the same Person base and extend from there. That's why the instance of
a Person might have some attributes and not others.
Leam
You have to ask yourself: composition or mixin? The easiest way is with a
mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to add to
the functionality of every instance of a class, I'm not sure that counts as
Decorator pattern?
If you want to do it with Composition, instead, have a look at the Ruby
documentation for Forwardable. (Sorry this is a bit rushed; chaotic
today...)
I think that this might be the article that originally clued me into
Decorator? Not sure: https://robots.thoughtbot.com/evaluating-alternative-
decorator-implementations-in
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<
http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data
protection regulations. Please refer to our website to view the ways in
which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data
protection regulations. Please refer to our website to view the ways in
which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-19 13:44:35 UTC
Permalink
<<<<<<<<
al = Person.new
Something_That_Changes_Character.new(al)
Something_Else_That_Also_Changes_Character.new(al)

In each case "al" has several attributes modified or added. The "al" passed to the second Something carries the modifications from the first.
<<<<<<<<

Modified – yes, added – no. Otherwise how will you know which attributes a1 has when you come to use it?




Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
leam hall
2018-07-19 13:52:20 UTC
Permalink
Post by Andy Jones
<<<<<<<<
al = Person.new
Something_That_Changes_Character.new(al)
Something_Else_That_Also_Changes_Character.new(al)
In each case "al" has several attributes modified or added. The "al"
passed to the second Something carries the modifications from the first.
<<<<<<<<
Modified – yes, added – no. Otherwise how will you know which attributes
a1 has when you come to use it?
The using program (game, creator, data) will track what it needs. So
CharacterData would have a schemaless datastore to include "Notes",
"Associates" and the like. "FreeTrader" the game would just use "Name, UPP,
Skills, Rank" and the like.

Some attributes are expected 90% of the time. For example, Skills is a hash
with a String:Int key:value pair. Instead of added everything to every
person, which seem bloated and ugly, I want to let the using program
add/modifiy what it needs.
leam hall
2018-07-19 18:33:17 UTC
Permalink
The overall plan is to get better at object oriented thinking and
programming. Trying to do that with Ruby since I enjoy it most of the
languages I've tried. I've done a few languages and gotten 3-6 months of
"experience" spread over 2-4 years each. Through the rest of 2018 I want to
just focus on OOP concepts and doings.

That's why the drive for patterns, TDD, using objects where structs would
be just as good, etc. Going overboard on OO to learn where it works and
where it doesn't.
Post by leam hall
Post by Andy Jones
<<<<<<<<
al = Person.new
Something_That_Changes_Character.new(al)
Something_Else_That_Also_Changes_Character.new(al)
In each case "al" has several attributes modified or added. The "al"
passed to the second Something carries the modifications from the first.
<<<<<<<<
Modified – yes, added – no. Otherwise how will you know which attributes
a1 has when you come to use it?
The using program (game, creator, data) will track what it needs. So
CharacterData would have a schemaless datastore to include "Notes",
"Associates" and the like. "FreeTrader" the game would just use "Name, UPP,
Skills, Rank" and the like.
Some attributes are expected 90% of the time. For example, Skills is a
hash with a String:Int key:value pair. Instead of added everything to every
person, which seem bloated and ugly, I want to let the using program
add/modifiy what it needs.
Andy Jones
2018-07-19 13:40:21 UTC
Permalink
The way Ruby thinks of OOP borrows a lot from Smalltalk.

I’m not a Smalltalk programmer, but the syntax is ridiculously easy to learn, and this book pays me back every time I read it: https://www.amazon.com/Smalltalk-Best-Practice-Patterns-Kent/dp/013476904X

(Although for gods’ sake don’t pay £50 for it 
)

From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org] On Behalf Of leam hall
Sent: 19 July 2018 14:29
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?

Hah! I may need a Smalltalk primer, I keep seeing references to it.

Yes, I think your last example is closer to the need and a Decorator might not be what I'm looking for. The simple explination is:

al = Person.new
Something_That_Changes_Character.new(al)
Something_Else_That_Also_Changes_Character.new(al)

In each case "al" has several attributes modified or added. The "al" passed to the second Something carries the modifications from the first.

Leam

On Thu, Jul 19, 2018 at 9:22 AM, Andy Jones <***@jameshall.co.uk<mailto:***@jameshall.co.uk>> wrote:
Well, first, it seems as if you might find it easier to keep the classes for character creation and the actual game somewhat different. Have the game read the JSON into a separate “model” class that keeps it away from the complexities of character creation, and just lets it deal with the resulting character? I don’t know.

Second, it seems to me that all your characters want to partake in all your addon functionality. The use case for Decorator Pattern is rather different. It’s popular in game design, but not usually used in that way, but rather like this:


flora = Character.new(“Flora the elven druid”)
flora.exend Elf
flora.exend Druid

varian = Character.new(“Varian the dwarven undead druid”)
varian.extend Dwarf
varian.extend Undead
varian.extend Druid


(Apologies if the formatting is odd, Outlook is playing Silly Devils)

If I understand correctly, you might want to go to what Smalltalk used to call “Method Classes” – where you farm off some of your functionality to a helper class that does a job, returns a result, and then never gets called again. It seems like your CharacterCreation might best be that sort of class. But I don’t know it well enough to say for sure.

class Person
def initialize(name, strength)
@name, @strength = name, strength
@foo = ValueOfFooFigurerOuter.new(strength).go
end
end

In the above example, the Person class doesn’t have to care how @foo is calculated. A helper class does that for it.

Hope that helps


From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org<mailto:ruby-talk-***@ruby-lang.org>] On Behalf Of leam hall
Sent: 19 July 2018 13:57
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?

Hmm..good question. This stems from my Traveller stuff and the game I'm writing, which have two different uses for the Person class. Here's the logic:

1. Every instance of Person
Has a name, gender, and UPP. (character stats)
Can be stored in a language agnostic manner (using JSON)

2. CharacterCreation adds to an instance of Person
Adds physical description, personality

3. Careers add to the instance of person
Skills, rank, notes, money, "stuff"
A character can go through multiple careers.

4. FreeTrader (the game) uses a limited subset of the Person + Additional stuff.
Ship position(role),
Game uses JSON
Uses Careers, might use CharacterCreation.

5. CharacterData (the database) stores as much information about each character as possible.
Planning to use Hanami/Sinatra? and a MongoDB backend.
Used to track details of characters for games and books I'm writing.

FreeTrader and CharacterData are separate projects but I want to build from the same Person base and extend from there. That's why the instance of a Person might have some attributes and not others.

Leam

On Thu, Jul 19, 2018 at 6:12 AM, Andy Jones <***@jameshall.co.uk<mailto:***@jameshall.co.uk>> wrote:
You have to ask yourself: composition or mixin? The easiest way is with a mixin, but it has limitations.

~~~~
module Engineer
def can_do_engines?; true; end
end

class Person
def initialize(name); @name = name; end
end

p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~

Note that you decorate an object --- not a class. If you want to add to the functionality of every instance of a class, I'm not sure that counts as Decorator pattern?

If you want to do it with Composition, instead, have a look at the Ruby documentation for Forwardable. (Sorry this is a bit rushed; chaotic today...)

I think that this might be the article that originally clued me into Decorator? Not sure: https://robots.thoughtbot.com/evaluating-alternative-decorator-implementations-in


-----Original Message-----
From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org<mailto:ruby-talk-***@ruby-lang.org>] On Behalf Of Leam Hall
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?

I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.

Haven't quite figured it out yet, thoughts?

Thanks!

Leam

Here's the error:
###
Traceback (most recent call last):
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
#<Person:0x0000562e9a870978 @data={:name=>"Al"}> (NoMethodError)
###


Code:
###
1 class Person
2 def initialize(data)
3 @data = data
4 end
5 def name
6 @data[:name] || "Fred"
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
16 @person = data[:person]
17 assign_role(data[:role])
18 end
19 def assign_role(role)
20 @person.role = role
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name<http://al.name>
30 #al.role = "Cadet Sergeant"
###
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org<mailto:ruby-talk-***@ruby-lang.org>?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org<mailto:ruby-talk-***@ruby-lang.org>?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>



Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.


Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org<mailto:ruby-talk-***@ruby-lang.org>?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>



Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
leam hall
2018-07-20 19:48:17 UTC
Permalink
This will be part of the weekend's joy.

There are lots of roles, and most instances of Person get at least one. A
few instances get more than one, but which role a particular instance gets
varies widely.

More questions as I stumble through...

Leam
Post by Andy Jones
You have to ask yourself: composition or mixin? The easiest way is with a
mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to add to
the functionality of every instance of a class, I'm not sure that counts as
Decorator pattern?
If you want to do it with Composition, instead, have a look at the Ruby
documentation for Forwardable. (Sorry this is a bit rushed; chaotic
today...)
I think that this might be the article that originally clued me into
Decorator? Not sure: https://robots.thoughtbot.com/evaluating-alternative-
decorator-implementations-in
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<
http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data
protection regulations. Please refer to our website to view the ways in
which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Leam Hall
2018-07-21 00:18:37 UTC
Permalink
And this is how I spend my Friday night...

Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.

####

class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end

module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end

module Relationships
def friends
@friends
end
def friends=(l)
if @friends.nil?
@friends = Array.new
end
@friends << l
end
end

class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end

### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank


####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin?  The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
  def can_do_engines?; true;  end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class.  If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable.  (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-implementations-in
<https://robots.thoughtbot.com/evaluating-alternative-decorator-implementations-in>
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
   1 class Person
   2   def initialize(data)
   4   end
   5   def name
   7   end
   8 end
   9
  10 class Role
  11   class Person
  12     attr_accessor :role
  13   end
  14
  15   def initialize(data)
  17     assign_role(data[:role])
  18   end
  19   def assign_role(role)
  21   end
  22 end
  23
  24 data = {:name => 'Al'}
  25
  26 al = Person.new(data)
  27 role_data = {:person => al, :role => 'Cadet'}
  28 Role.new(role_data)
  29 puts al.name <http://al.name>
  30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lis
Andy Jones
2018-07-23 07:26:54 UTC
Permalink
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.

Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.

The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another
class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Leam Hall
2018-07-24 09:58:16 UTC
Permalink
Understood. Here's how I see that being dealt with.

1. There is a Universal Data Store (UDS) of some unrestricted format.
JSON, MOngoDB, or whatever. Each program pulls from the same data store.

2. The character generate program creates basic characters.

3. The game program:
For a new game, generates crew. Thus uses the basic character
generation program and adds specific stuff required by the game.
For a saved game, those characters are pulled from the UDS.

4. The fiction tracker program:
For new characters:
Does basic character generation
Adds data like appearance, mental workup, last known location, etc.
Otherwise pulls the data from the UDS.
Allows manual edits of data.
Allows creation of new data fields.

5. The relationship tracker feeds data into Neo4J.
A basic character from #2 has no relational data.
A game character from #3 would have the rest of the crew as
relationships.
A fiction character might overload Neo4J, if you've seen how
convoluted my fiction gets...

In each case the programs include the modules they need. The UDS has
*all* the data, but each program only uses parts of it. The relationship
tracker doesn't care about physical appearance, etc.

By keeping things in modules, each program can use the modules it needs.
Does that solve the problems you are seeing?

I really appreciate the feedback, you are helping clarify my thinking.

Leam
Post by Andy Jones
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.
Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.
The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another
class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-24 10:08:18 UTC
Permalink
Well, your UDS will have to put the player data in an object of some class. If not Player, then what?

Put another way, when an object "pulls data from the UDS" -- where does it hold it?

Generally speaking when reading from a data store you want one of more "models" -- objects that represent the data to the rest of the application. It's fine if you don't want Player to be the model, but whatever "models" player information to the rest of the application will need that rank attribute (and all the others from all those decorators) or you will have the same problem.

-----Original Message-----
From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org] On Behalf Of Leam Hall
Sent: 24 July 2018 10:58
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?

Understood. Here's how I see that being dealt with.

1. There is a Universal Data Store (UDS) of some unrestricted format.
JSON, MOngoDB, or whatever. Each program pulls from the same data store.

2. The character generate program creates basic characters.

3. The game program:
For a new game, generates crew. Thus uses the basic character
generation program and adds specific stuff required by the game.
For a saved game, those characters are pulled from the UDS.

4. The fiction tracker program:
For new characters:
Does basic character generation
Adds data like appearance, mental workup, last known location, etc.
Otherwise pulls the data from the UDS.
Allows manual edits of data.
Allows creation of new data fields.

5. The relationship tracker feeds data into Neo4J.
A basic character from #2 has no relational data.
A game character from #3 would have the rest of the crew as
relationships.
A fiction character might overload Neo4J, if you've seen how
convoluted my fiction gets...

In each case the programs include the modules they need. The UDS has
*all* the data, but each program only uses parts of it. The relationship
tracker doesn't care about physical appearance, etc.

By keeping things in modules, each program can use the modules it needs.
Does that solve the problems you are seeing?

I really appreciate the feedback, you are helping clarify my thinking.

Leam
Post by Andy Jones
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.
Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.
The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another
class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Leam Hall
2018-07-24 11:01:18 UTC
Permalink
Let me see if I can come up with some sample code in the next few days.
Doing the Udemy "Ruby Metaprogramming" class and my brain is melting...
Post by Andy Jones
Well, your UDS will have to put the player data in an object of some class. If not Player, then what?
Put another way, when an object "pulls data from the UDS" -- where does it hold it?
Generally speaking when reading from a data store you want one of more "models" -- objects that represent the data to the rest of the application. It's fine if you don't want Player to be the model, but whatever "models" player information to the rest of the application will need that rank attribute (and all the others from all those decorators) or you will have the same problem.
-----Original Message-----
Sent: 24 July 2018 10:58
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Understood. Here's how I see that being dealt with.
1. There is a Universal Data Store (UDS) of some unrestricted format.
JSON, MOngoDB, or whatever. Each program pulls from the same data store.
2. The character generate program creates basic characters.
For a new game, generates crew. Thus uses the basic character
generation program and adds specific stuff required by the game.
For a saved game, those characters are pulled from the UDS.
Does basic character generation
Adds data like appearance, mental workup, last known location, etc.
Otherwise pulls the data from the UDS.
Allows manual edits of data.
Allows creation of new data fields.
5. The relationship tracker feeds data into Neo4J.
A basic character from #2 has no relational data.
A game character from #3 would have the rest of the crew as
relationships.
A fiction character might overload Neo4J, if you've seen how
convoluted my fiction gets...
In each case the programs include the modules they need. The UDS has
*all* the data, but each program only uses parts of it. The relationship
tracker doesn't care about physical appearance, etc.
By keeping things in modules, each program can use the modules it needs.
Does that solve the problems you are seeing?
I really appreciate the feedback, you are helping clarify my thinking.
Leam
Post by Andy Jones
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.
Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.
The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another
class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-24 13:44:42 UTC
Permalink
Post by Leam Hall
Doing the Udemy "Ruby Metaprogramming" class and my brain is melting...
Metaprogramming will do that to you. To be usually filed under "too clever by half", and only occasionally justifiable...



Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
leam hall
2018-07-24 13:50:10 UTC
Permalink
Post by Andy Jones
Post by Leam Hall
Doing the Udemy "Ruby Metaprogramming" class and my brain is melting...
Metaprogramming will do that to you. To be usually filed under "too
clever by half", and only occasionally justifiable...
Oddly enough it's explaining some things that have confused me for a long
time. Of course, it's also adding twice that number of confusing things...
Leam Hall
2018-07-27 10:18:56 UTC
Permalink
Hey Andy, this is my pre-workday proof of concept. Lots of ways to
improve it, I'm sure. Instead of a formal DB connection I'm using JSON
and passing it around. The last bit takes in the JSON and uses just what
it needs. In reality, the code would add a career to the Person if there
wasn't already one. I just wanted to see if I could pass the data around
well.

Where there is a "# blah...blah" after a puts or a to_s, that's the output.

Does this answer the questions you raised?

Thanks!

Leam


#####

class Person
require 'json'
def initialize()
@name = 'Al'
@age = 14
@gender = 'Female'
end
def to_s
puts "#{@name} is a #{@age} year old #{@gender}."
end
def to_j
@record = {:name => @name, :age => @age, :gender => @gender}
@record.to_json
end
end

al = Person.new
al.to_s # Al is a 14 year old Female.
puts al.to_j # {"name":"Al","age":14,"gender":"Female"}

module Appearance
def hair
@hair = 'Raider cut dishwater blond'
end
def frame
@frame = 'skinny'
end
def appearance_update
hair
frame
app_record = {:hair => @hair, :frame => @frame}
@record = @record.merge(app_record)
@record.to_json
end
end

al.extend Appearance
al.appearance_update

module Cadet
def rank
@rank = 'Cadet Sergeant'
end
def age
@age += 1
end
def career_to_s
rank
age
puts "#{@name} is a #{@age} year old #{@gender} #{@rank}."
end
def career_to_j
@career_record = {:age => @age, :rank => @rank}
@record = @record.merge(@career_record)
@record.to_json
end
end

al.extend Cadet
al.career_to_s # Al is a 15 year old Female Cadet Sergeant.
al_json = al.career_to_j

puts al_json #
{"name":"Al","age":15,"gender":"Female","hair":"Raider cut dishwater
blond","frame":"skinny","rank":"Cadet Sergeant"}

class Crew
require 'json'
def initialize(data)
@data = JSON.parse(data, :symbolize_names => true)
@name = @data[:name]
@rank = @data[:rank]
end
def to_s
puts "Welcome aboard, #{@rank} #{@name}!"
end
end
my_crew = Crew.new(al_json)
my_crew.to_s # Welcome aboard, Cadet Sergeant Al!

#####
Post by Andy Jones
Well, your UDS will have to put the player data in an object of some class. If not Player, then what?
Put another way, when an object "pulls data from the UDS" -- where does it hold it?
Generally speaking when reading from a data store you want one of more "models" -- objects that represent the data to the rest of the application. It's fine if you don't want Player to be the model, but whatever "models" player information to the rest of the application will need that rank attribute (and all the others from all those decorators) or you will have the same problem.
-----Original Message-----
Sent: 24 July 2018 10:58
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Understood. Here's how I see that being dealt with.
1. There is a Universal Data Store (UDS) of some unrestricted format.
JSON, MOngoDB, or whatever. Each program pulls from the same data store.
2. The character generate program creates basic characters.
For a new game, generates crew. Thus uses the basic character
generation program and adds specific stuff required by the game.
For a saved game, those characters are pulled from the UDS.
Does basic character generation
Adds data like appearance, mental workup, last known location, etc.
Otherwise pulls the data from the UDS.
Allows manual edits of data.
Allows creation of new data fields.
5. The relationship tracker feeds data into Neo4J.
A basic character from #2 has no relational data.
A game character from #3 would have the rest of the crew as
relationships.
A fiction character might overload Neo4J, if you've seen how
convoluted my fiction gets...
In each case the programs include the modules they need. The UDS has
*all* the data, but each program only uses parts of it. The relationship
tracker doesn't care about physical appearance, etc.
By keeping things in modules, each program can use the modules it needs.
Does that solve the problems you are seeing?
I really appreciate the feedback, you are helping clarify my thinking.
Leam
Post by Andy Jones
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.
Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.
The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another
class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-27 10:54:42 UTC
Permalink
1) All your classes output JSON, which is nice, but you don't show any classes that read that JSON, and I'm pretty certain that at that point you will find you want a single object, a Person model, to read in the JSON and represent it to the rest of the code. (And if you are going to do that later, you might as well do that now?)

2a) If all your person objects get decorated with Appearance and Cadet, then there is no point using Decorator Pattern. You might as well put it all in one class. Or use some other way to split up the code, which I agree might be a good idea if that is your intent. (Method Classes still seem the way to go, for me, in that eventuality.)

2b) If only some of the person objects get decorated, then you will never be able to call `person.rank` safely because you won't know if the object has a rank method or not. If this isn't a problem because you never plan to use these objects once they have built JSON for you, then you might as well just have a class to build JSON for you, and not represent person as an object at all. Which brings us back to (1).

TL;DR: My recommendation would be: Design the object that needs to read and represent all this JSON about a person first. Call _that_ the Person class, and work from there. It might clarify your thinking, and probably make for much shorter code.

Hope that helps...

-----Original Message-----
From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org] On Behalf Of Leam Hall
Sent: 27 July 2018 11:19
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?

Hey Andy, this is my pre-workday proof of concept. Lots of ways to
improve it, I'm sure. Instead of a formal DB connection I'm using JSON
and passing it around. The last bit takes in the JSON and uses just what
it needs. In reality, the code would add a career to the Person if there
wasn't already one. I just wanted to see if I could pass the data around
well.

Where there is a "# blah...blah" after a puts or a to_s, that's the output.

Does this answer the questions you raised?

Thanks!

Leam


#####

class Person
require 'json'
def initialize()
@name = 'Al'
@age = 14
@gender = 'Female'
end
def to_s
puts "#{@name} is a #{@age} year old #{@gender}."
end
def to_j
@record = {:name => @name, :age => @age, :gender => @gender}
@record.to_json
end
end

al = Person.new
al.to_s # Al is a 14 year old Female.
puts al.to_j # {"name":"Al","age":14,"gender":"Female"}

module Appearance
def hair
@hair = 'Raider cut dishwater blond'
end
def frame
@frame = 'skinny'
end
def appearance_update
hair
frame
app_record = {:hair => @hair, :frame => @frame}
@record = @record.merge(app_record)
@record.to_json
end
end

al.extend Appearance
al.appearance_update

module Cadet
def rank
@rank = 'Cadet Sergeant'
end
def age
@age += 1
end
def career_to_s
rank
age
puts "#{@name} is a #{@age} year old #{@gender} #{@rank}."
end
def career_to_j
@career_record = {:age => @age, :rank => @rank}
@record = @record.merge(@career_record)
@record.to_json
end
end

al.extend Cadet
al.career_to_s # Al is a 15 year old Female Cadet Sergeant.
al_json = al.career_to_j

puts al_json #
{"name":"Al","age":15,"gender":"Female","hair":"Raider cut dishwater
blond","frame":"skinny","rank":"Cadet Sergeant"}

class Crew
require 'json'
def initialize(data)
@data = JSON.parse(data, :symbolize_names => true)
@name = @data[:name]
@rank = @data[:rank]
end
def to_s
puts "Welcome aboard, #{@rank} #{@name}!"
end
end
my_crew = Crew.new(al_json)
my_crew.to_s # Welcome aboard, Cadet Sergeant Al!

#####
Post by Andy Jones
Well, your UDS will have to put the player data in an object of some class. If not Player, then what?
Put another way, when an object "pulls data from the UDS" -- where does it hold it?
Generally speaking when reading from a data store you want one of more "models" -- objects that represent the data to the rest of the application. It's fine if you don't want Player to be the model, but whatever "models" player information to the rest of the application will need that rank attribute (and all the others from all those decorators) or you will have the same problem.
-----Original Message-----
Sent: 24 July 2018 10:58
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Understood. Here's how I see that being dealt with.
1. There is a Universal Data Store (UDS) of some unrestricted format.
JSON, MOngoDB, or whatever. Each program pulls from the same data store.
2. The character generate program creates basic characters.
For a new game, generates crew. Thus uses the basic character
generation program and adds specific stuff required by the game.
For a saved game, those characters are pulled from the UDS.
Does basic character generation
Adds data like appearance, mental workup, last known location, etc.
Otherwise pulls the data from the UDS.
Allows manual edits of data.
Allows creation of new data fields.
5. The relationship tracker feeds data into Neo4J.
A basic character from #2 has no relational data.
A game character from #3 would have the rest of the crew as
relationships.
A fiction character might overload Neo4J, if you've seen how
convoluted my fiction gets...
In each case the programs include the modules they need. The UDS has
*all* the data, but each program only uses parts of it. The relationship
tracker doesn't care about physical appearance, etc.
By keeping things in modules, each program can use the modules it needs.
Does that solve the problems you are seeing?
I really appreciate the feedback, you are helping clarify my thinking.
Leam
Post by Andy Jones
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.
Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.
The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another
class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Leam Hall
2018-07-27 23:49:06 UTC
Permalink
Post by Andy Jones
1) All your classes output JSON, which is nice, but you don't show any classes that read that JSON, and I'm pretty certain that at that point you will find you want a single object, a Person model, to read in the JSON and represent it to the rest of the code. (And if you are going to do that later, you might as well do that now?)
Check out "class Crew" near the end. It takes in JSON and sets
attributes based on values. In theory it could be more complex code, but
that's the basics.
Post by Andy Jones
2a) If all your person objects get decorated with Appearance and Cadet, then there is no point using Decorator Pattern. You might as well put it all in one class. Or use some other way to split up the code, which I agree might be a good idea if that is your intent. (Method Classes still seem the way to go, for me, in that eventuality.)
Not all will, and there are lots of cases where there will be very
minimal details. For example, something like this (mostly pseudo code.)

stranger = Person.new
"You get a message from #{stranger.name}. #{stranger.gender == 'M' ?
'He' : 'She'} seems to know a lot about what you're doing."
Post by Andy Jones
2b) If only some of the person objects get decorated, then you will never be able to call `person.rank` safely because you won't know if the object has a rank method or not. If this isn't a problem because you never plan to use these objects once they have built JSON for you, then you might as well just have a class to build JSON for you, and not represent person as an object at all. Which brings us back to (1).
Each program needs certain data about the instance. An instance of Crew
needs rank and skills, so it would pull in the JSON and test for those
things. If they did not exist, use the shared Character_Tools module to
generate them. Each program only needs to ensure what it needs is there.
Post by Andy Jones
TL;DR: My recommendation would be: Design the object that needs to read and represent all this JSON about a person first. Call _that_ the Person class, and work from there. It might clarify your thinking, and probably make for much shorter code.
That was the original design but it kept growing into a mess. Using at
hoc modules seems to clean it up.

Leam
Post by Andy Jones
Hope that helps...
-----Original Message-----
Sent: 27 July 2018 11:19
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Hey Andy, this is my pre-workday proof of concept. Lots of ways to
improve it, I'm sure. Instead of a formal DB connection I'm using JSON
and passing it around. The last bit takes in the JSON and uses just what
it needs. In reality, the code would add a career to the Person if there
wasn't already one. I just wanted to see if I could pass the data around
well.
Where there is a "# blah...blah" after a puts or a to_s, that's the output.
Does this answer the questions you raised?
Thanks!
Leam
#####
class Person
require 'json'
def initialize()
@name = 'Al'
@age = 14
@gender = 'Female'
end
def to_s
end
def to_j
@record = {:name => @name, :age => @age, :gender => @gender}
@record.to_json
end
end
al = Person.new
al.to_s # Al is a 14 year old Female.
puts al.to_j # {"name":"Al","age":14,"gender":"Female"}
module Appearance
def hair
@hair = 'Raider cut dishwater blond'
end
def frame
@frame = 'skinny'
end
def appearance_update
hair
frame
@record = @record.merge(app_record)
@record.to_json
end
end
al.extend Appearance
al.appearance_update
module Cadet
def rank
@rank = 'Cadet Sergeant'
end
def age
@age += 1
end
def career_to_s
rank
age
end
def career_to_j
@career_record = {:age => @age, :rank => @rank}
@record = @record.merge(@career_record)
@record.to_json
end
end
al.extend Cadet
al.career_to_s # Al is a 15 year old Female Cadet Sergeant.
al_json = al.career_to_j
puts al_json #
{"name":"Al","age":15,"gender":"Female","hair":"Raider cut dishwater
blond","frame":"skinny","rank":"Cadet Sergeant"}
class Crew
require 'json'
def initialize(data)
@data = JSON.parse(data, :symbolize_names => true)
@name = @data[:name]
@rank = @data[:rank]
end
def to_s
end
end
my_crew = Crew.new(al_json)
my_crew.to_s # Welcome aboard, Cadet Sergeant Al!
#####
Post by Andy Jones
Well, your UDS will have to put the player data in an object of some class. If not Player, then what?
Put another way, when an object "pulls data from the UDS" -- where does it hold it?
Generally speaking when reading from a data store you want one of more "models" -- objects that represent the data to the rest of the application. It's fine if you don't want Player to be the model, but whatever "models" player information to the rest of the application will need that rank attribute (and all the others from all those decorators) or you will have the same problem.
-----Original Message-----
Sent: 24 July 2018 10:58
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Understood. Here's how I see that being dealt with.
1. There is a Universal Data Store (UDS) of some unrestricted format.
JSON, MOngoDB, or whatever. Each program pulls from the same data store.
2. The character generate program creates basic characters.
For a new game, generates crew. Thus uses the basic character
generation program and adds specific stuff required by the game.
For a saved game, those characters are pulled from the UDS.
Does basic character generation
Adds data like appearance, mental workup, last known location, etc.
Otherwise pulls the data from the UDS.
Allows manual edits of data.
Allows creation of new data fields.
5. The relationship tracker feeds data into Neo4J.
A basic character from #2 has no relational data.
A game character from #3 would have the rest of the crew as
relationships.
A fiction character might overload Neo4J, if you've seen how
convoluted my fiction gets...
In each case the programs include the modules they need. The UDS has
*all* the data, but each program only uses parts of it. The relationship
tracker doesn't care about physical appearance, etc.
By keeping things in modules, each program can use the modules it needs.
Does that solve the problems you are seeing?
I really appreciate the feedback, you are helping clarify my thinking.
Leam
Post by Andy Jones
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.
Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.
The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another
class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Leam Hall
2018-07-28 14:09:42 UTC
Permalink
Ah...I may be understanding. Slowly. Let me see if I have it.

1. There is a file called 'person.rb' that sets the basic Person class.
class Person
def initialize(data)
@name = data[:name]
end
end

2. There is a program called "Starship" that uses 'crew.rb', a file that
opens the Person class.
class Person
attr_reader :rank
def setup_crew(data)
@rank = data[:rank]
end
end

3. Starship looks something like this:
# Create data from UDS pull.
data = {:name => 'Al', :rank => 'Captain'}

al = Person.new(data)
require 'crew'
al.setup_crew(data)
puts al.rank # "Captain" She was promoted. :)

Is that what you're suggesting? I can pull the data from the UDS, put it
into a hash, and then send it to each "setup_" method.

Leam
Post by Andy Jones
1) All your classes output JSON, which is nice, but you don't show any classes that read that JSON, and I'm pretty certain that at that point you will find you want a single object, a Person model, to read in the JSON and represent it to the rest of the code. (And if you are going to do that later, you might as well do that now?)
2a) If all your person objects get decorated with Appearance and Cadet, then there is no point using Decorator Pattern. You might as well put it all in one class. Or use some other way to split up the code, which I agree might be a good idea if that is your intent. (Method Classes still seem the way to go, for me, in that eventuality.)
2b) If only some of the person objects get decorated, then you will never be able to call `person.rank` safely because you won't know if the object has a rank method or not. If this isn't a problem because you never plan to use these objects once they have built JSON for you, then you might as well just have a class to build JSON for you, and not represent person as an object at all. Which brings us back to (1).
TL;DR: My recommendation would be: Design the object that needs to read and represent all this JSON about a person first. Call _that_ the Person class, and work from there. It might clarify your thinking, and probably make for much shorter code.
Hope that helps...
-----Original Message-----
Sent: 27 July 2018 11:19
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Hey Andy, this is my pre-workday proof of concept. Lots of ways to
improve it, I'm sure. Instead of a formal DB connection I'm using JSON
and passing it around. The last bit takes in the JSON and uses just what
it needs. In reality, the code would add a career to the Person if there
wasn't already one. I just wanted to see if I could pass the data around
well.
Where there is a "# blah...blah" after a puts or a to_s, that's the output.
Does this answer the questions you raised?
Thanks!
Leam
#####
class Person
require 'json'
def initialize()
@name = 'Al'
@age = 14
@gender = 'Female'
end
def to_s
end
def to_j
@record = {:name => @name, :age => @age, :gender => @gender}
@record.to_json
end
end
al = Person.new
al.to_s # Al is a 14 year old Female.
puts al.to_j # {"name":"Al","age":14,"gender":"Female"}
module Appearance
def hair
@hair = 'Raider cut dishwater blond'
end
def frame
@frame = 'skinny'
end
def appearance_update
hair
frame
@record = @record.merge(app_record)
@record.to_json
end
end
al.extend Appearance
al.appearance_update
module Cadet
def rank
@rank = 'Cadet Sergeant'
end
def age
@age += 1
end
def career_to_s
rank
age
end
def career_to_j
@career_record = {:age => @age, :rank => @rank}
@record = @record.merge(@career_record)
@record.to_json
end
end
al.extend Cadet
al.career_to_s # Al is a 15 year old Female Cadet Sergeant.
al_json = al.career_to_j
puts al_json #
{"name":"Al","age":15,"gender":"Female","hair":"Raider cut dishwater
blond","frame":"skinny","rank":"Cadet Sergeant"}
class Crew
require 'json'
def initialize(data)
@data = JSON.parse(data, :symbolize_names => true)
@name = @data[:name]
@rank = @data[:rank]
end
def to_s
end
end
my_crew = Crew.new(al_json)
my_crew.to_s # Welcome aboard, Cadet Sergeant Al!
#####
Post by Andy Jones
Well, your UDS will have to put the player data in an object of some class. If not Player, then what?
Put another way, when an object "pulls data from the UDS" -- where does it hold it?
Generally speaking when reading from a data store you want one of more "models" -- objects that represent the data to the rest of the application. It's fine if you don't want Player to be the model, but whatever "models" player information to the rest of the application will need that rank attribute (and all the others from all those decorators) or you will have the same problem.
-----Original Message-----
Sent: 24 July 2018 10:58
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Understood. Here's how I see that being dealt with.
1. There is a Universal Data Store (UDS) of some unrestricted format.
JSON, MOngoDB, or whatever. Each program pulls from the same data store.
2. The character generate program creates basic characters.
For a new game, generates crew. Thus uses the basic character
generation program and adds specific stuff required by the game.
For a saved game, those characters are pulled from the UDS.
Does basic character generation
Adds data like appearance, mental workup, last known location, etc.
Otherwise pulls the data from the UDS.
Allows manual edits of data.
Allows creation of new data fields.
5. The relationship tracker feeds data into Neo4J.
A basic character from #2 has no relational data.
A game character from #3 would have the rest of the crew as
relationships.
A fiction character might overload Neo4J, if you've seen how
convoluted my fiction gets...
In each case the programs include the modules they need. The UDS has
*all* the data, but each program only uses parts of it. The relationship
tracker doesn't care about physical appearance, etc.
By keeping things in modules, each program can use the modules it needs.
Does that solve the problems you are seeing?
I really appreciate the feedback, you are helping clarify my thinking.
Leam
Post by Andy Jones
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.
Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.
The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another
class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-30 07:29:11 UTC
Permalink
-----Original Message-----
From: ruby-talk [mailto:ruby-talk-***@ruby-lang.org] On Behalf Of Leam Hall
Sent: 28 July 2018 15:10
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?

Ah...I may be understanding. Slowly. Let me see if I have it.

1. There is a file called 'person.rb' that sets the basic Person class.
class Person
def initialize(data)
@name = data[:name]
end
end

2. There is a program called "Starship" that uses 'crew.rb', a file that
opens the Person class.
class Person
attr_reader :rank
def setup_crew(data)
@rank = data[:rank]
end
end

3. Starship looks something like this:
# Create data from UDS pull.
data = {:name => 'Al', :rank => 'Captain'}

al = Person.new(data)
require 'crew'
al.setup_crew(data)
puts al.rank# "Captain" She was promoted. :)

Is that what you're suggesting? I can pull the data from the UDS, put it
into a hash, and then send it to each "setup_" method.

Leam
Post by Andy Jones
1) All your classes output JSON, which is nice, but you don't show any classes that read that JSON, and I'm pretty certain that at that point you will find you want a single object, a Person model, to read in the JSON and represent it to the rest of the code. (And if you are going to do that later, you might as well do that now?)
2a) If all your person objects get decorated with Appearance and Cadet, then there is no point using Decorator Pattern. You might as well put it all in one class. Or use some other way to split up the code, which I agree might be a good idea if that is your intent. (Method Classes still seem the way to go, for me, in that eventuality.)
2b) If only some of the person objects get decorated, then you will never be able to call `person.rank` safely because you won't know if the object has a rank method or not. If this isn't a problem because you never plan to use these objects once they have built JSON for you, then you might as well just have a class to build JSON for you, and not represent person as an object at all. Which brings us back to (1).
TL;DR: My recommendation would be: Design the object that needs to read and represent all this JSON about a person first. Call _that_ the Person class, and work from there. It might clarify your thinking, and probably make for much shorter code.
Hope that helps...
-----Original Message-----
Sent: 27 July 2018 11:19
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Hey Andy, this is my pre-workday proof of concept. Lots of ways to
improve it, I'm sure. Instead of a formal DB connection I'm using JSON
and passing it around. The last bit takes in the JSON and uses just what
it needs. In reality, the code would add a career to the Person if there
wasn't already one. I just wanted to see if I could pass the data around
well.
Where there is a "# blah...blah" after a puts or a to_s, that's the output.
Does this answer the questions you raised?
Thanks!
Leam
#####
class Person
require 'json'
def initialize()
@name = 'Al'
@age = 14
@gender = 'Female'
end
def to_s
end
def to_j
@record = {:name => @name, :age => @age, :gender => @gender}
@record.to_json
end
end
al = Person.new
al.to_s # Al is a 14 year old Female.
puts al.to_j # {"name":"Al","age":14,"gender":"Female"}
module Appearance
def hair
@hair = 'Raider cut dishwater blond'
end
def frame
@frame = 'skinny'
end
def appearance_update
hair
frame
@record = @record.merge(app_record)
@record.to_json
end
end
al.extend Appearance
al.appearance_update
module Cadet
def rank
@rank = 'Cadet Sergeant'
end
def age
@age += 1
end
def career_to_s
rank
age
end
def career_to_j
@career_record = {:age => @age, :rank => @rank}
@record = @record.merge(@career_record)
@record.to_json
end
end
al.extend Cadet
al.career_to_s # Al is a 15 year old Female Cadet Sergeant.
al_json = al.career_to_j
puts al_json #
{"name":"Al","age":15,"gender":"Female","hair":"Raider cut dishwater
blond","frame":"skinny","rank":"Cadet Sergeant"}
class Crew
require 'json'
def initialize(data)
@data = JSON.parse(data, :symbolize_names => true)
@name = @data[:name]
@rank = @data[:rank]
end
def to_s
end
end
my_crew = Crew.new(al_json)
my_crew.to_s # Welcome aboard, Cadet Sergeant Al!
#####
Post by Andy Jones
Well, your UDS will have to put the player data in an object of some class. If not Player, then what?
Put another way, when an object "pulls data from the UDS" -- where does it hold it?
Generally speaking when reading from a data store you want one of more "models" -- objects that represent the data to the rest of the application. It's fine if you don't want Player to be the model, but whatever "models" player information to the rest of the application will need that rank attribute (and all the others from all those decorators) or you will have the same problem.
-----Original Message-----
Sent: 24 July 2018 10:58
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
Understood. Here's how I see that being dealt with.
1. There is a Universal Data Store (UDS) of some unrestricted format.
JSON, MOngoDB, or whatever. Each program pulls from the same data store.
2. The character generate program creates basic characters.
For a new game, generates crew. Thus uses the basic character
generation program and adds specific stuff required by the game.
For a saved game, those characters are pulled from the UDS.
Does basic character generation
Adds data like appearance, mental workup, last known location, etc.
Otherwise pulls the data from the UDS.
Allows manual edits of data.
Allows creation of new data fields.
5. The relationship tracker feeds data into Neo4J.
A basic character from #2 has no relational data.
A game character from #3 would have the rest of the crew as
relationships.
A fiction character might overload Neo4J, if you've seen how
convoluted my fiction gets...
In each case the programs include the modules they need. The UDS has
*all* the data, but each program only uses parts of it. The relationship
tracker doesn't care about physical appearance, etc.
By keeping things in modules, each program can use the modules it needs.
Does that solve the problems you are seeing?
I really appreciate the feedback, you are helping clarify my thinking.
Leam
Post by Andy Jones
Again, I'm dubious that this is the best approach, because when you get an unknown method error half way into your main, game code, and it turns out that that's because you called person.rank on a Person that doesn't have the Career_Tools mixin, that is going to be painful to debug.
Alternatively you will have to pepper your code with things like `if defined?(person.rank); rank_thing(person.rank); end` which will make the code much harder to follow and ALL the bugs harder to find.
The way I would do it, personally? I know that some Persons have a rank. So I put rank right there in the Person class. Civilians have a rank of nil. Nil values are a PITA but considerably less so than missing methods! So now I can at least do `rank_thing(person.rank)` and I guess rank_thing starts with `return unless rank`...
Post by Andy Jones
-----Original Message-----
Sent: 21 July 2018 1:19 am
To: Ruby users
Subject: Re: Class that opens and adds variables to instances of another class?
And this is how I spend my Friday night...
Thoughts? In this case Career_Tools has to account for anything in any
of the careers. Most of the time those things are pretty simple.
####
class Person
def initialize(data)
@name = data[:name]
end
def name
@name
end
end
module Career_Tools
def rank
@rank
end
def rank=(career)
@rank = career.ranks
end
end
module Relationships
def friends
@friends
end
def friends=(l)
@friends = Array.new
end
@friends << l
end
end
class Cadet
def ranks
['Cadet', 'Cadet Corporal', 'Cadet Sergeant', 'Cadet
Leiutenant'].sample
end
end
### main
person_data = {:name => 'Al'}
al = Person.new(person_data)
puts al.name
al.extend Career_Tools
al.extend Relationships
al.friends = "CC One"
al.friends = "Wilbur"
puts al.friends.join(", ")
career = Cadet.new
al.rank=(career)
puts al.rank
####
Post by leam hall
This will be part of the weekend's joy.
There are lots of roles, and most instances of Person get at least one.
A few instances get more than one, but which role a particular instance
gets varies widely.
More questions as I stumble through...
Leam
You have to ask yourself: composition or mixin? The easiest way is
with a mixin, but it has limitations.
~~~~
module Engineer
def can_do_engines?; true; end
end
class Person
end
p = Person.new("fred")
p.extend Engineer
puts p.can_do_engines?
~~~~
Note that you decorate an object --- not a class. If you want to
add to the functionality of every instance of a class, I'm not sure
that counts as Decorator pattern?
If you want to do it with Composition, instead, have a look at the
Ruby documentation for Forwardable. (Sorry this is a bit rushed;
chaotic today...)
I think that this might be the article that originally clued me into
https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in
Post by leam hall
<https://robots.thoughtbot.com/evaluating-alternative-decorator-
implementations-in>
Post by leam hall
-----Original Message-----
Sent: 19 July 2018 10:59
To: Ruby users
Subject: Class that opens and adds variables to instances of another
class?
I think I'm trying to figure out the Decorator pattern. What I want is
to have a <thing> that takes an instance of <something> and changes it.
The changes can include modifying and adding instance variables.
Haven't quite figured it out yet, thoughts?
Thanks!
Leam
###
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for
###
###
1 class Person
2 def initialize(data)
4 end
5 def name
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
17 assign_role(data[:role])
18 end
19 def assign_role(role)
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name <http://al.name>
30 #al.role = "Cadet Sergeant"
###
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
Click here to view Company Information and Confidentiality
Notice.<http://www.jameshall.co.uk/index.php/small-print/email-
disclaimer
Post by leam hall
<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>>
Please note that we have updated our privacy policy in line with new
data protection regulations. Please refer to our website to view the
ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-30 07:29:24 UTC
Permalink
TL;DR: Okay, look, if it were me I _really_ wouldn't do it this way, because it's going to be hell on wheels to debug. You're free to do it how you like, of course, but...
2. There is a program called "Starship" that uses 'crew.rb', a file that
opens the Person class.
<<<<<<<<

Now every time you look at code that uses Person you will have to work out whether that code has also required crew.rb previously, because that will change the behaviour of Person. (In addition to working out which decorators were run on the specific instance of Person you are looking at...)

For my money it's much, much better to put the definition of Person in one file, person.rb, and know it won't change during the project. This is kind of fundamental to OOP, IMO: a class is a thing. It's not one of two things, depending.
3. Starship looks something like this:
# Create data from UDS pull.
data = {:name => 'Al', :rank => 'Captain'}
<<<<<<<<

Where is this JSON data coming from? Does every class have the responsibility of parsing that JSON file? What if sections of that JSON file end up requiring non-trivial code to parse -- how many classes will that effect? If the format of the JSON file actually changes, how many classes will you have to change?

Again, in my opinion it's way better to have a single class that parses the JSON and creates a person from it. Then pass instances of that class to the other classes, not the JSON data.

Again, this is kind of fundamental to OOP: the "Single Responsibility Principal". Each class should do just one thing.

IMO the logical name for the class that represents person data to the rest of the application is ... Person. That's your person class.


Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
leam hall
2018-07-30 14:34:32 UTC
Permalink
Yes, changes to Person and the JSON data will propagate. Already did
that with the UPP going from a string of Hexidecimals to a Hash of
Int.

However, there's really just one Person class. The data is passed to
it to create the base person object and then supplementary modules are
mixed in to expand the methods and attributes Person is aware of.
Post by Andy Jones
TL;DR: Okay, look, if it were me I _really_ wouldn't do it this way, because it's going to be hell on wheels to debug. You're free to do it how you like, of course, but...
2. There is a program called "Starship" that uses 'crew.rb', a file that
opens the Person class.
<<<<<<<<
Now every time you look at code that uses Person you will have to work out whether that code has also required crew.rb previously, because that will change the behaviour of Person. (In addition to working out which decorators were run on the specific instance of Person you are looking at...)
For my money it's much, much better to put the definition of Person in one file, person.rb, and know it won't change during the project. This is kind of fundamental to OOP, IMO: a class is a thing. It's not one of two things, depending.
# Create data from UDS pull.
data = {:name => 'Al', :rank => 'Captain'}
<<<<<<<<
Where is this JSON data coming from? Does every class have the responsibility of parsing that JSON file? What if sections of that JSON file end up requiring non-trivial code to parse -- how many classes will that effect? If the format of the JSON file actually changes, how many classes will you have to change?
Again, in my opinion it's way better to have a single class that parses the JSON and creates a person from it. Then pass instances of that class to the other classes, not the JSON data.
Again, this is kind of fundamental to OOP: the "Single Responsibility Principal". Each class should do just one thing.
IMO the logical name for the class that represents person data to the rest of the application is ... Person. That's your person class.
Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Leam Hall
2018-08-01 08:00:06 UTC
Permalink
Funny note: I had set POODR down for a week or two (or three). Picked it
up last night before bed and read a section on hook methods which may
exactly solve this issue. Code when I have it.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Elizabeth Amisano
2018-08-21 19:07:49 UTC
Permalink
Hello,
I am looking for a system to create a program that will help my daughter
learn to read. It will be a program that follows certain rules she is
learning with her tutor.

Two examples of a command I would ask the program to do would be to:

-highlight all vowels in the text that are backed up by a consonant
yellow....

-3 letters that are between highlight to red


I am brand new to coding but am determined to make a program that allows me
to input the text she will be reading and then based on the rule that is
learned in tutoring, apply them one at a time, then layer.

If there are any suggestions folks have for a system to use I would greatly
appreciate it.
Thank you
Elizabeth Amisano
Post by Leam Hall
Funny note: I had set POODR down for a week or two (or three). Picked it
up last night before bed and read a section on hook methods which may
exactly solve this issue. Code when I have it.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Nicola Mingotti
2018-08-21 23:57:08 UTC
Permalink
Hi Elizabeth,

so, I wrote you a very simple program that goes in the direction
you say. You can see a screenshot here :
Loading Image...

The code is at the bottom.

1] I put a lot of comments to simplify your reading

2] There is some stuff in italian, forgive me is 2:00 am, in the next
days i will
have other stuff to do, so now or never;) Anyhow, GoogleTranslate where
needed ;)

3] I wrote it fast, about 2 hours, it took me most of the time to find
how to make the graphical interface do what i want to.

4] The graphical interface i like for scripting is Tk, probably the
simplest.

5] since i wrote it fast, it should be easier to understand than well
written code.
But, consider this is just a script, not a serius program, it is just to
get your started.

6] I am really interested in knowing if you can run the program. Please
let me know that. I need to know if a non-programmer can run a Ruby program
with a simple interface, since we discussed about this recently in the list.

7] There are tons of typos, sorry for that.


enough cha cha cha, here is the script

========================
#!/usr/local/bin/ruby
# ; -*- mode: Ruby;-*-

require "irb"
require "irb/completion"

require "tk"
require "tk/font"

root = TkRoot.new { title "Text Hilighter" }

# size and place of the window
root.minsize [500, 100]
root.geometry "+300+300"

# first push button
b1 = TkButton.new root do
  text "Hilight Stuff" ;
  command proc { pushedHilight; }
  pack :side => "top", :fill => "x", :expand => "true"
end

# second push button
b2 = TkButton.new root do
  text "Clean Highligthing" ;
  command proc { pushedCleanHighlighting; }
  pack :side => "top", :fill => "x", :expand => "true"
end

# text widget, where you write stuff
# here it is a global variable because we need to access it from functions
$t1 = TkText.new root do
  pack :side => "top", :fill => "both", :expand => "true"
end

# ---- some commands for Tk Text widget -----
# $t1.insert :end "helo"    # inserisce una parola alla fine
# $t1.delte 1.0, :end       # cacella tutto
# $t1.get 1.0, :end         # ottiene tutto il testo
# $t1.tag_add :xx, 1.0, 1.2      # taggo con :xx i primi due caratteri
nella prima riga
# $t1.tag_configure :xx, :background, "yellow"     # il tag :xx viene
impostato a background yellow
# $t1.tag_delete :xx        # elimina i tag dal testo
# $t1.index :end            # ritorna con x.y che e' l'ultimo carattere


def pushedHilight
  # pattern, that says: I want all strings starting with any of the
letter a,e,i,o,u
  # and followed by any of the letter {b,c,d, ... }
  # the "i" at the ends means we ignore case of letters
  pattern = /[aeiou][bcdfghjklmnpqrstvwyz]/i
  puts "pushed button: Hilight"
  # get all the text from the Tk Text widget
  text = $t1.get 1.0, :end
  # split the text in lines
  lines = text.split /\n/;
  # iterate over each lines looking for the pattern we are interested into
  (0...lines.length).each do |idx|
    # lines in a Tk Text widget are numbered starting from 1
(unfortunately)
    # but charactes in each line are numbered starting from 0 (we like
this more)
    tclLineIdx = idx + 1
    # "li" is the line i am currently observing
    li = lines[idx]
    puts "line: #{idx} -- #{li}"
    # "pe" (pattern end) at the beginnig is set to zero, we have not
found still any
    # pattern.
    pe = 0
    # now we look for all pattern occurring in "li"
    loop do
      pb = li.index(pattern, pe)
      # if no pattern is found "pb" (pattern begin) is "nil", we can
exit the study
      # of the current line.
      break if pb == nil
      pe  = Regexp.last_match.end(0)
      puts "line #{idx},  pb: #{pb}, pe: #{pe} "
      # this line is the one telling to Tk to mark each patter with the
tag :xx (just a random name)
      $t1.tag_add :xx, "#{tclLineIdx}.#{pb}", "#{tclLineIdx}.#{pe-1}"
    end
  end
  # here we say that what is tagged as tag ":xx" must be hilighted in
yellow
  $t1.tag_configure :xx, :background, "yellow"
end

def pushedCleanHighlighting
  puts "pushed button: Clean-Hilight"
  # delete all tags, so remove all hilights
  $t1.tag_delete :xx
end

# this thing is usefull for debugging and learn Ruby
# decomment next line when studying.
# Thread.new {  IRB.start(__FILE__) }

# start the event loop (waits for button pushed and other events)
Tk.mainloop;

========================
Post by Elizabeth Amisano
Hello,
 I am looking for a system to create a program that will help my
daughter learn to read. It will be a program that follows certain
rules she is learning with her tutor.
-highlight all vowels in the text that are backed up by a consonant
yellow....
-3 letters that are between highlight to red
I am brand new to coding but am determined to make a program that
allows me to input the text she will be reading and then based on the
rule that is learned in tutoring, apply them one at a time, then layer.
If there are any suggestions folks have for a system to use I would
greatly appreciate it.
Thank you
Elizabeth Amisano
Funny note: I had set POODR down for a week or two (or three). Picked it
up last night before bed and read a section on hook methods which may
exactly solve this issue. Code when I have it.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
--
--------------------------
Dr. Nicola Mingotti
R&D - Borghi Srl
CTO - BondInsider
--------------------------
Dmitriy Non
2018-07-28 23:05:45 UTC
Permalink
Hi!

Sorry, I didn't read the whole thread. I was just curious what was the initial question.

I have some thoughts/advices/opinions on this:

* Role::Person naming is just bad. I had to actually read the implementation to understand
what it is.I advice you not to use same constant names in Ruby. Even though it doesnt really "break" ruby
you can shoot yourself in a leg with it.
* Well, at this point I know that I got a wrong idea about what you were trying to achieve.
Problem in your code is that you think `class Role; class Person ...` actually changes original Person class.
Well, it doesn't (I guess someone already pointed that for you). Classes are namespaces too, so `Person` and `Role::Person`
are actually absolutely different constants that are not connected in any way.
* I like the idea of "mutability is bad". It really helps you to write better code.
So don't mutate original instance with decorators. Try using more "classic" (or java-ish) approach:
```
class Person
# ...
end

class PersonWithRole
attr_accessor :role
attr_reader :decorated_person
# it's from rails but you get the idea
delegate :name, to: :decorated_person

def initialize(person)
@decorated_person = person
end

# ...
end
```
Decorator is like a wrapper over some object that provides additional functionality.
My `PersonWithRole` does not even care about implementation of decorated person. It just adds `role` accessor
that is stored in wrapper itself and proxies method calls to wrapped object (I did it with `delegate` but I guess
that `method_missing` is better approach).
If you want different namespace for decorators you can try something like `PersonDecorators::WithRole`

You should definetely read about Ruby constant lookup. I actually wrote a post on the toppic but it's in russian:(
I recommend you to read:

* Chapter 7.9 of "The Ruby Programming Language" (from Matz)
* https://guides.rubyonrails.org/autoloading_and_reloading_constants.html
* Play around with [Module.nesting](http://ruby-doc.org/core-2.2.0/Module.html#method-c-nesting)

I hope my late letter will be helpful. Sorry for my english

--------------------------------------
Dmitriy Non
***@gmail.com



On 19 Jul 2018, at 12:58, Leam Hall <***@gmail.com> wrote:

I think I'm trying to figure out the Decorator pattern. What I want is to have a <thing> that takes an instance of <something> and changes it. The changes can include modifying and adding instance variables.

Haven't quite figured it out yet, thoughts?

Thanks!

Leam

Here's the error:
###
Traceback (most recent call last):
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for #<Person:0x0000562e9a870978 @data={:name=>"Al"}> (NoMethodError)
###


Code:
###
1 class Person
2 def initialize(data)
3 @data = data
4 end
5 def name
6 @data[:name] || "Fred"
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
16 @person = data[:person]
17 assign_role(data[:role])
18 end
19 def assign_role(role)
20 @person.role = role
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name
30 #al.role = "Cadet Sergeant"
###

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Dmitriy Non
2018-07-28 23:18:55 UTC
Permalink
I forgot to mention that "classic" decorators are nice because
they compose just fine as long as they don't have colliding public methods.

For example:

```
class Person
def say_hi; 'hi!' end
end

class PersonDecorator
attr_reader :decorated_person
def initialize(person)
@decorated_person = person
end

# just send other calls to original person
def method_missing(m, *args, &block)
decorated_person.send(m, *args, &block)
end
end

class PersonWithName < PersonDecorator
attr_reader :name
def initialize(person, name)
super(person)
@name = name
end
end

class PersonWithAge < PersonDecorator
attr_reader :age
def initialize(person, age)
super(person)
@age = age
end
end

person = PersonWithName.new(PersonWithAge.new(Person.new, 18), 'John Doe')
puts person.name
puts person.age
puts person.say_hi
```

Though there may be some problems when you are overriding original methods
but I am sure you will know how to solve this issue when you face it.

--------------------------------------
Dmitriy Non
***@gmail.com



On 29 Jul 2018, at 02:05, Dmitriy Non <***@gmail.com> wrote:

Hi!

Sorry, I didn't read the whole thread. I was just curious what was the initial question.

I have some thoughts/advices/opinions on this:

* Role::Person naming is just bad. I had to actually read the implementation to understand
what it is.I advice you not to use same constant names in Ruby. Even though it doesnt really "break" ruby
you can shoot yourself in a leg with it.
* Well, at this point I know that I got a wrong idea about what you were trying to achieve.
Problem in your code is that you think `class Role; class Person ...` actually changes original Person class.
Well, it doesn't (I guess someone already pointed that for you). Classes are namespaces too, so `Person` and `Role::Person`
are actually absolutely different constants that are not connected in any way.
* I like the idea of "mutability is bad". It really helps you to write better code.
So don't mutate original instance with decorators. Try using more "classic" (or java-ish) approach:
```
class Person
# ...
end

class PersonWithRole
attr_accessor :role
attr_reader :decorated_person
# it's from rails but you get the idea
delegate :name, to: :decorated_person

def initialize(person)
@decorated_person = person
end

# ...
end
```
Decorator is like a wrapper over some object that provides additional functionality.
My `PersonWithRole` does not even care about implementation of decorated person. It just adds `role` accessor
that is stored in wrapper itself and proxies method calls to wrapped object (I did it with `delegate` but I guess
that `method_missing` is better approach).
If you want different namespace for decorators you can try something like `PersonDecorators::WithRole`

You should definetely read about Ruby constant lookup. I actually wrote a post on the toppic but it's in russian:(
I recommend you to read:

* Chapter 7.9 of "The Ruby Programming Language" (from Matz)
* https://guides.rubyonrails.org/autoloading_and_reloading_constants.html
* Play around with [Module.nesting](http://ruby-doc.org/core-2.2.0/Module.html#method-c-nesting)

I hope my late letter will be helpful. Sorry for my english

--------------------------------------
Dmitriy Non
***@gmail.com



On 19 Jul 2018, at 12:58, Leam Hall <***@gmail.com> wrote:

I think I'm trying to figure out the Decorator pattern. What I want is to have a <thing> that takes an instance of <something> and changes it. The changes can include modifying and adding instance variables.

Haven't quite figured it out yet, thoughts?

Thanks!

Leam

Here's the error:
###
Traceback (most recent call last):
3: from test_decorator.rb:28:in `<main>'
2: from test_decorator.rb:28:in `new'
1: from test_decorator.rb:17:in `initialize'
test_decorator.rb:20:in `assign_role': undefined method `role=' for #<Person:0x0000562e9a870978 @data={:name=>"Al"}> (NoMethodError)
###


Code:
###
1 class Person
2 def initialize(data)
3 @data = data
4 end
5 def name
6 @data[:name] || "Fred"
7 end
8 end
9
10 class Role
11 class Person
12 attr_accessor :role
13 end
14
15 def initialize(data)
16 @person = data[:person]
17 assign_role(data[:role])
18 end
19 def assign_role(role)
20 @person.role = role
21 end
22 end
23
24 data = {:name => 'Al'}
25
26 al = Person.new(data)
27 role_data = {:person => al, :role => 'Cadet'}
28 Role.new(role_data)
29 puts al.name
30 #al.role = "Cadet Sergeant"
###

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>



Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Loading...