Руби сеттер идиома - PullRequest
3 голосов
/ 30 ноября 2009

Я работаю над классом Chart, и у него есть параметр margin, который содержит значения :top, :bottom, :right и :left. Моим первым вариантом было сделать margin установщиком и установить значения следующим образом:

# Sets :left and :right margins and doesn't alter :top and :bottom 
chart.margins = {:left => 10, :right => 15}

Это хорошо, потому что это явно сеттер, но, подумав, я думаю, это тоже может сбить с толку: пользователь может подумать, что поля содержат только значения :left и :right, что неправильно. Другой вариант - исключить = и сделать его обычным методом:

chart.margins(:left => 10, :right => 15)

С помощью этого синтаксиса легко понять, что происходит, но он не является стандартным установщиком и конфликтует с margins геттером. И есть еще один вариант:

chart.margins(:left, 10)
chart.margins(:right, 15)

Я не знаю, что об этом думать. Для меня очевидно, что метод является установщиком, но на этот раз я не могу установить несколько значений одним вызовом, и снова возникает проблема с геттером. Я относительно новичок в Ruby и еще не привык ко всем идиомам. Итак, что вы думаете, ребята? Какой самый лучший вариант?

Ответы [ 5 ]

5 голосов
/ 30 ноября 2009

Вы также можете создать класс Margin, чтобы использовать следующий понятный синтаксис:

class Margin
    attr_accessor :left, :right, :top, :bottom
    ...
end

class Chart
    attr_accessor :margins
    ...
 end


chart.margins.left = 10
puts chart.margins.right
3 голосов
/ 30 ноября 2009

Не уверен, что это тот синтаксис, который вы хотели бы сделать доступным (извините, если нет:)

#!/usr/bin/ruby
class Margins < Struct.new(:top, :bottom, :left, :right) 
end

class Chart
  attr_reader :margins

  def initialize()
    @margins = Margins.new(0,0,0,0)
  end

  def margins=(hash)
    [:top, :bottom, :left, :right].each do |dir|
      if (hash[dir])
        @margins[dir] = hash[dir]
      end
    end
  end
end

c = Chart.new
c.margins.left = 10
c.margins={:top=>12,:bottom=>13}
puts c.margins.left
# 10
puts c.inspect;
# #<Chart:0xb7caaf8c @margins=#<struct Margins top=12, bottom=13, left=10, right=0>>

# However c.margins.foo = 12 would give you an error
2 голосов
/ 30 ноября 2009

Я не думаю, что создание класса для Margin - это перебор. Вы всегда можете представить его значения в виде хэша, используя to_hash или что-то подобное.

Также, если хотите, вы можете заставить его работать в стиле DSL:

chart.margins do |m|
  m.left 10
  m.right 20
  m.vertical 5 # sets both top and bottom margin
end

Но, думаю, я бы все равно выбрал подход парадигмы ...

2 голосов
/ 30 ноября 2009

В дополнение к ответу парадигмы вы можете добавить в класс Margins метод для поддержки:

chart.margins.set :left => 10, :right => 15

Вы можете расширить метод margins = для обработки числового аргумента:

chart.margins = 20

как сахар для:

chart.margins = Margins.new(20, 20, 20, 20)
1 голос
/ 30 ноября 2009

Вы также можете придерживаться того, что у вас было раньше, и использовать обычный синтаксис хеша.

margins["left"] = 10  #to set just one without changing the others
...