2

I have a ruby script (pretty big one) that update a couple of dbs using SQL. Most of the sql queries (and even table names), are constant, and look like:

MONTH = 8
SOME_TABLE = "the_table_name_" + MONTH + SOME_SUFFIX
SOME_QUERY = "CREATE TEMPORARY TABLE #{SOME_TABLE} SELECT yada, yada2 FROM #{SOME_OTHER_TABLE} WHERE yada=1 AND MONTH=#{MONTH};"

There are hundreds of queries and tables like that, and they all use each other. I made a recent change, to get the "month" as a parameter from the command line instead a constant in the command line, so run this script in a cron management system.

My first problem was that i couldn't set MONTH as a const. At first place, i worked around it with something like:

eval("MONTH=%d" % options[:month])

later on i changed MONTH to be @month (global) and that fixed that.

the second and main problem was than my main.rb has that line

require("queries.rb")

at the beginning, therefore ruby tries to expand the var MONTH (or @month) when requiring, before my main even ran! I worked around that problem using that code:

def run_lazy_loaded_work
    require './queries.rb'
    run_work
end

and removing the require in the start of the file of course. that solution works perfectly, since the expansion in queries.rb happens when requiring, after @month has already been set.

However, It doesn't smell like the correct solution, and feels like a nasty patch, which might not be bullet proof when other developer will take ownership of that code.

I tried to initialize all the queries in a config class, which initializes all the queries in the instance's initialization, and has accessors to that, but since that's hundreds of lines, and also all the lines that are using them, it becomes even nastier.

I would love to hear if anyone can think of a more elegance solution.

Thanks! :)

* UPDATE ** I've edited it a bit more, and currently it looks like that:

main.rb:

require './work.rb'
def main
    run_work(options)
end

work.rb:

def run_work(options)
    @month=options[:month]
    load 'queries.rb'
    run_query(SOME_QUERY, SOME_TABLE, SOME_INDEX)
end

queries.rb:

SOME_TABLE = "table_name_#{@month}"
SOME_QUERY = "SELECT * FROM #{SOME_TABLE} WHERE month=#{month}"
4

2 に答える 2

3

queries.rb考えられる解決策の1つは、高価なプロパティが実際には「偽の」定数ではなくメソッドになるように変更することです。そうすれば、要求queries.rbするのに費用はかからず、コードを次のように変更します。

require queries.rb

#...

def run_lazy_loaded_work
    run_work(Queries.some_query())
end

「数百」のプロパティを持つファイルを変更するのは少し怖いように思えるかもしれませんが、一定のように見えますが、実際にはそれほど怖くないようです。

于 2012-08-21T17:01:48.367 に答える
0

私は2セントを与えようとします。

定数とインスタンス変数を使用する代わりに、メソッドを使用できます。

メソッドが初めて呼び出されると、内部ヘルパー インスタンス変数の値が定義されます。そのため、月は必要な場合にのみ展開されます。

元。:

def month
  # set @month at first time; or return it in further calls
  @month ||= $options[:month]     # here I'm using a global $options
end

(...)

# will get the month (will define it at first call)
SOME_TABLE = "the_table_name_" + month + SOME_SUFFIX
于 2012-08-21T20:07:37.207 に答える