1

I'm trying to create a new hash called $player[:abil_mods] which is based on my $player[:abils] hash. It should take each value, subtract 10, divide by 2, and assign it to an identical key in the new hash. However, it doesn't seem to be editing the values in $player[:abil_mods].

My code:

$player = {
  abils: {str: 20, con: 20, dex: 14, wis: 12, int: 8, cha: 8},
  abil_mods: {}
}

$player[:abil_mods] = $player[:abils].each { |abil, pts| ((pts - 10) / 2).floor }

should create the following $player[:abil_mods] hash:

abil_mods: {str: 5, con: 5, dex: 2, wis: 1, int: -1, cha: -1}

but it is instead creating:

abil_mods: {str: 20, con: 20, dex: 14, wis: 12, int: 8, cha: 8}
Richard
  • 164
  • 7
  • Odds are really good that using a global `$player` is not the right thing to do. The vast majority of the time people use globals when they don't understand variable scoping because a global will step around scope issues, but it opens a big hole for bugs and problems later in your code. I'd recommend spending more time getting to understand why, and why not, you should use them. – the Tin Man Nov 16 '19 at 20:35

3 Answers3

2

I'm pretty sure #each returns the hash it's operating on. (At least that's how it works on arrays...) It's more about doing something with each entry than about returning the results of that something.

You might try instead:

$player[:abil_mods] = $player[:abils].transform_values { |pts| ((pts - 10) / 2).floor }
cHao
  • 84,970
  • 20
  • 145
  • 172
1

Just use map instead of each in this line:

$player[:abil_mods] = $player[:abils].map { |abil, pts| ((pts - 10) / 2).floor }

each iterates over the array but return the original array. Whereas map returns the new values.

Btw: Using global variables (the one with the $) is almost every time a bad idea. Using instance of local variables is preferred.

spickermann
  • 100,941
  • 9
  • 101
  • 131
  • Gotcha, thanks. Why is using global variables a bad idea? I've only ever heard that it's not very Ruby to use them. – Richard Nov 16 '19 at 14:43
  • 4
    The problem with global variables is that, not only are they visible anywhere in the code for a program, they can also be changed from anywhere in the application. This can make tracking bugs difficult. I would argue that such a global variable and global state is a code smell. – spickermann Nov 16 '19 at 14:50
1

The problem is that in the line

$player[:abil_mods] = $player[:abils].each { |abil, pts| ((pts - 10) / 2).floor }

you are assigning the return value of the method Hash#each that is self to the the Hash $player at key :abil_mods. In your case the Hash is referenced by $player[:abils].

You could use Enumerable#map which returns an array that can be easily converted to a hash:

$player[:abil_mods] = $player[:abils].map { |k, pts| [k,  ((pts - 10) / 2).floor] }.to_h
the Tin Man
  • 158,662
  • 42
  • 215
  • 303