Обойти недостаток контекста в методах маршрута Синатры - PullRequest
7 голосов
/ 22 ноября 2011

У меня возникла проблема с отсутствующими экземплярами и ошибками nilClass при вызове моих маршрутов. После изучения источника, кажется, что вызов generate_method в основном создает новый метод, используя блок исходного метода.

get "/" do
    @some_local_instance.do_something()
end

Таким образом, в вышеприведенном методе вполне может быть локальная переменная внутри этого класса, называемая some_local_instance, однако, когда rote фактически вычисляется, у нее нет контекста относительно того, где был определен метод, поэтому он потерпит неудачу.

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

class SomeRouteClass
    def initialize(sinatra, calculator)
        @calculator = calculator
        @sinatra = sinatra
    end

    def setup_routes
        @sinatra.get "/add" do
            return @calculator.add(1,1)
        end
    end
end

class Calculator
    def add(a,b)
        return a+b;
    end
end

sinatra = Sinatra.new
calculator = Calculator.new

routing_class = SomeRouteClass.new(sinatra, calculator)
routing_class.setup_routes

sinatra.run!

Простите за любые орфографические / синтаксические ошибки, это всего лишь быстрый пример, но, как вы можете видеть, класс регистрирует маршруты, и когда этот маршрут ударил, возвращает некоторое значение, сгенерированное экземпляром калькулятора, который он принял при создании его экземпляра.

Проблема, с которой я столкнулся, заключается в том, что в этом примере, когда я пытаюсь запустить маршрут / add, он говорит мне, что @calculator - это nilClass, и я полагаю, что это сводится к тому, что Sinatra просто берет блок кода без контекста. , Это кажется подходящим для любого простого рендеринга шаблонов, но если вам нужно сделать что-то более причудливое или вы хотите, чтобы ваш код был модульным, без использования статики и одиночных кодов, у вас, похоже, нет никакого способа обойти это ...

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

== Редактировать ==

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

Ответы [ 3 ]

0 голосов
/ 24 ноября 2011

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

Кажется, что большинство основныхБиблиотеки Ruby работают против статических экземпляров (или констант), которые затем используются для настройки ... это все же кажется мне немного странным, как с точки зрения поставщика базы данных.Очень просто вызвать статический класс вашей базы данных и подключиться к вашей базе данных, а затем начать запрашивать, однако что если вам нужно подключиться к 2 отдельным базам данных одновременно.Вам нужно будет поменять местами серверы с тем же статическим классом, что было бы проблематично.

В любом случае это кажется на данный момент, как ответ - просто сделайте константу для всего, что вам нужно представитьмаршрут, а затем, когда вы тестируете, просто установите этот const на макет.Все еще кажется немного сумасшедшим, называя эти вещи «константами», когда на самом деле они не являются константами в истинном смысле этого слова, поскольку их можно изменить в любое время ... как и многие вещи для новых разработчиков ruby, это просто сбивает с толку радиэто (то есть elsif, @@ blah, переменная case, определяющая, является ли ее константной или нет).

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

0 голосов
/ 08 января 2012

Блок, переданный в get, оценивается в другом контексте, чем объект Calculator.Синатра, вероятно, зовет instance_eval или одного из ее двоюродных братьев.Однако должна быть возможность захвата локальных переменных из окружающей области, используя что-то вроде следующего (непроверенного, увы) подхода:

def setup_routes
    calculator = @calculator
    @sinatra.get "/add" do
        return calculator.add(1,1)
    end
end
0 голосов
/ 22 ноября 2011
class SomeRouteClass
    def initialize(sinatra, calculator)
        @calculator = calculator
        @sinatra = sinatra
    end

    def calculator
        @calculator
    end

    def setup_routes
        @sinatra.get "/add" do
            return calculator.add(1,1)
        end
    end
end
...