Существуют некоторые фундаментальные заблуждения о том, как Ruby OOP работает в вашем примере, и без полного примера кода и возможности опрашивать вас о том, что вы пытаетесь выполнить, sh трудно навести вас к что может быть наиболее подходящим ответом. Любой ответ, который я даю, будет основан частично на опыте, а частично на мнении, поэтому вы можете увидеть и другие ответы.
На высоком уровне у вас должны быть классы в модулях, а не модули в классах. Хотя вы можете помещать модули в классы, вы лучше понимаете , почему вы делаете это , прежде чем делать это.
Далее, модули и методы, которые вы в них определили, не автоматически становятся доступными для экземпляров родительского класса, поэтому client.Bikes
никогда не будет работать, потому что Ruby ожидает найти метод экземпляра с именем Bikes
внутри класса Api
; он не будет искать модуль с таким именем.
Единственный способ получить доступ к определенным вами модулям и методам модулей - это использовать их на уровне класса / модуля. Поэтому, если у вас есть это:
class Foo
module Bar
def baz
puts 'foobarbaz'
end
end
end
Вы можете сделать это на уровне класса / модуля:
Foo::Bar.baz
foobarbaz
=> nil
Но вы не можете ничего сделать на уровне экземпляра:
Foo.new::Bar.baz
TypeError: #<Foo:0x00007fa037d39260> is not a class/module
Foo.new.Bar.baz
NoMethodError: undefined method `Bar' for #<Foo:0x00007fa037162e28>
Итак, если вы до сих пор понимаете, почему структура вашего примера не работает, тогда вы можете работать над созданием чего-то более разумного. Давайте начнем с именования и структуры класса / модуля.
Во-первых, Api
здесь является плохим именем, потому что вы обычно будете использовать Api
для чего-то, что предоставляет API, а не подключается к одному, поэтому я бы рекомендовал сделать имя более описательным и использовать модуль, чтобы указать, что вы инкапсулируете один или несколько связанных классов:
module MonthyApiClient
end
Далее, я бы порекомендовал добавить Client
класс для инкапсуляции всего, что связано с созданием экземпляра клиента, используемого для подключения к API:
module MonthyApiClient
class Client
def initialize
@client = nil # insert your logic here
@connection = nil # insert your logic here
end
end
end
Отношения между client
и connection
в вашем примере кода не ясны, поэтому для простоты я представим, что их можно объединить в один класс (Client
) и что мы отбрасываем модуль Authentication
полностью.
Далее нам нужен разумный способ объединения module Bikes
и * 1041. * в этот код. Не имеет смысла преобразовывать их в классы, потому что нет необходимости создавать их экземпляры. Это чисто вспомогательные функции, которые делают что-то для экземпляра Client
, поэтому они должны быть методами экземпляра в этом классе:
module MonthyApiClient
class Client
def initialize
# insert your logic here
@client = nil
@connection = nil
end
def create_bike
# insert your logic here
# e.g., @connection.post(something)
end
def delete_bike
# insert your logic here
# e.g., @connection.delete(something)
end
def create_phone
# insert your logic here
# e.g., @connection.post(something)
end
end
end
Обратите внимание, что мы поменяли new
на create
; Вы не хотите называть метод new
в Ruby, и в контексте, который мы используем, new
будет означать создание экземпляра, но не сохранять новый объект , тогда как create
будет означает создание и сохранение нового объекта .
И теперь, когда мы здесь, и теперь, когда мы удалили все вложенные модули, переместив их логику c в другое место, мы можем обратите внимание, что родительский модуль, который мы установили изначально, является излишне избыточным и может устранить его:
class MonthyApiClient
def initialize
# insert your logic here
@client = nil
@connection = nil
end
def create_bike
# insert your logic here
# e.g., @connection.post(something)
end
def delete_bike
# insert your logic here
# e.g., @connection.delete(something)
end
def create_phone
# insert your logic here
# e.g., @connection.post(something)
end
end
Тогда вы сможете достичь sh вашей первоначальной цели:
client_one = MonthyApiClient.new
client_one.create_bike
client_two = MonthyApiClient.new
client_two.create_phone
Проработав это объяснение, я думаю, ваш оригинальный код - это пример того, как вы тратите много времени на преждевременную чрезмерную оптимизацию. Лучше спланировать бизнес-логику c и сделать ее максимально простой. На https://softwareengineering.stackexchange.com/a/80094 есть некоторая полезная информация, которая может помочь объяснить эту концепцию.
Я даже пропустил попытки оптимизировать код, который я здесь показал, потому что я точно не знаю, как Существует много общего между созданием и удалением велосипедов и телефонов. С этим функциональным классом и с лучшим пониманием другого кода в этом приложении я мог бы попытаться DRY его запустить (и это может означать возвращение к модулю с классом Client
и или методы модуля или другие классы для инкапсуляции DRY logi c), но было бы преждевременным пытаться.
Ваш последний вопрос был о том, как структурировать файлы и каталоги для модулей и классов, и я бы направил вас к Идеальная ruby структура проекта (среди многих других вопросов на этом сайте) для получения дополнительной информации.