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,以使昂贵的属性实际上是方法而不是“假”常量。然后要求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 回答