Возврат, содержащий экземпляр объекта в ruby

Я пытаюсь реализовать напуганную версию цепочки методов. Возврат экземпляра класса после каждого вызова функции прост, вы просто делаете

def chainable_method
    some_code()
    self
end

Моя идея состоит в том, что методы, которые вы можете вызывать, зависят от предыдущего вызова метода. Я пытаюсь добиться этого, возвращая объект, принадлежащий содержащему объекту. Содержащийся объект будет иметь несколько специальных методов, а затем реализует метод method_missing для возврата экземпляра содержащего объекта.

Изменить: дочерний объект имеет связанное с ним состояние, которое должно быть само по себе, а не родительское. Возможно, раньше было неясно, почему мне нужен целый экземпляр только для вызовов методов.

super не имеет значения в этом случае, потому что содержащийся объект не наследуется от содержащего объекта, и я бы все равно не хотел вызывать методы содержащего объекта для содержащегося объекта - я хочу вызывать методы содержащего объекта для самого содержащего объекта . Мне нужен содержащий объект, а не содержащий объектный класс.

Не уверен, что это возможно.

Изменить: все перефразировано, чтобы использовать «содержащий/содержащийся объект» вместо совершенно неправильного родительского/дочернего объекта. Кроме того, я использую 1.9.3, если это имеет значение. Версия значения не имеет, могу поменять если нужно.

Мое объяснение, вероятно, было неясным. Вот код:

class AliasableString
    def initialize(string)
        @string = string
    end

    def as(aka)
        @aka = aka
    end

    def has_aka?
        [email protected]?
    end

    # alias is a reserved word
    def aka
        @aka
    end

    def to_s
        @string + (self.has_aka? ? (" as " + @aka) : "")
    end
end

class Query
    def initialize
        @select_statements = Array.new
    end

    def select(statement)
        select_statement = AliasableString.new(statement)
        @select_statements.push(select_statement)
        select_statement
    end

    def print
        if @select_statements.size != 0
            puts "select"
            @select_statements.each_with_index {| select, i|
                puts select
            }
        end
    end
end

# Example usage

q0 = Query.new

q0.select("This is a select statement")
    .select("Here's another one")
        .as("But this one has an alias")
    .select("This should be passed on to the parent!")

q0.print

Я еще не полностью реализовал print. Для AliasableString необходимо, чтобы @string и @aka были разделены, чтобы я мог разделить их позже.


person some guy    schedule 30.01.2014    source источник
comment
Разместите родительский и дочерний классы.   -  person jcm    schedule 30.01.2014
comment
Не существует «родительского экземпляра». Есть только экземпляр. Либо вы хотите вернуть Parent.new, либо у вас уже есть экземпляр parent, и вы можете его вернуть.   -  person Aleksei Matiushkin    schedule 30.01.2014
comment
the child object doesn't inherit from the parent ... I want the parent instance, not the parent class ... ват.   -  person Jake Romer    schedule 30.01.2014
comment
Я знаю. Я вырезаю здесь слово «родитель». Я не был уверен, как еще это описать.   -  person some guy    schedule 30.01.2014
comment
Родительский класс может иметь много экземпляров, и как именно дочерний класс не наследует от своего родителя? Я думаю, что здесь есть некоторая концептуальная путаница, которую нужно прояснить (по крайней мере, я в замешательстве). Может быть, вам нужен модуль или одноэлементный класс?   -  person Jake Romer    schedule 30.01.2014
comment
В коде экземпляр Query — это то, что я называю родителем. Запрос может иметь кучу AliasableStrings. Но AliasableString не наследуется от Query. Какая фраза лучше? Содержащий объект?   -  person some guy    schedule 30.01.2014
comment
Сделать конструктор AliasableString получающим второй параметр: экземпляр Query: select_statement = AliasableString.new(statement, self).   -  person Aleksei Matiushkin    schedule 30.01.2014


Ответы (1)


Прежде всего, не имеет значения, какой класс объекта содержится в экземпляре Query. Весь синтаксис, показанный в разделе «Примеры использования», соответствующим образом определен в Query. Единственное требование к объектам, содержащимся в экземпляре запроса, состоит в том, чтобы они реагировали на as (или какой-либо аналогичный метод). Здесь у вас есть что-то вроде конечного автомата, но единственное состояние, которое действительно имеет значение, это то, что какой-то объект занимает последнюю позицию в массиве select_statements. Вот как я бы это построил (опять же, основываясь в основном на вашем примере в конце, боюсь, я не могу полностью следовать вашему первоначальному объяснению):

class Query
  # ... initialize, etc.

  def select(statement, statement_class = AliasableString)
    select_statements << statement_class.new(statement)
    self
  end

  def as(aka)
    # this will only ever be used on the most recent statement added
    statement_to_alias = select_statements.last

    # throw an error if select_statements is empty (i.e., :last returns nil)
    raise 'You must add a statement first' unless statement_to_alias

    # forward the message on to the statement
    statement_to_alias.as(aka)

    # return the query object again to permit further chaining
    self
  end
end

AliasableString не нужно ничего знать о Query; все, что ему нужно сделать, это соответствующим образом отреагировать на as.

person Zach Kemp    schedule 30.01.2014
comment
Это работает, и это имеет больше смысла/проще, чем любой другой вариант, который я мог придумать. Я пойду с этим. Спасибо! Единственная проблема, которую я вижу, заключается в том, что это может сломаться, если несколько объектов работают с одним запросом одновременно — например, с потоками — но моя конечная цель — просто автоматически генерировать действительно повторяющиеся запросы HiveQL. Я не могу придумать ни одной реальной жизненной ситуации, в которой это могло бы стать проблемой. - person some guy; 30.01.2014