更新时间:2023-12-05 19:43:28
我认为您可能对 require
的工作方式感到困惑.当您调用 require
时,首先 Ruby 会检查该文件是否已被需要,如果是则直接返回.如果没有,则运行文件的内容,但与 require
语句不在同一范围内.换句话说,使用 require
与将 require
语句替换为文件的内容(是em> 例如,C 的 #include
是如何工作的).
在您的情况下,当您需要 ~/.twitter_auth.rb
文件时,正在创建 @client
实例变量,但作为顶部的实例变量级别 main
对象,不是作为 TwitterFeed
实例的实例变量,其中 require
被称为表单.>
您可以做一些事情,例如将 Twitter::Client
对象分配给一个常量,然后您可以从 render
方法中引用该常量:
MyClient = Twitter::Client.new{...
然后
需要'~/twitter_auth.rb'@client = 我的客户...
我建议这只是为了解释 require
发生的事情,这不是一个很好的技术.
我认为更好的选择是将您的凭据以简单的数据格式保存在您的主目录中,然后从您的脚本中读取它们并使用它们创建 Twitter 客户端.在这种情况下,Yaml 可能会完成这项工作.
首先将您的 ~/twitter_auth.rb
替换为看起来像这样的 ~/twitter_auth.yaml
:
:consumer_key: "CEoYXXXXXXXXXXXX":consumer_secret: "apnHXXXXXXXXXXXXXXXXXXXXXXXX":oauth_token: "105XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX":oauth_token_secret: "BJ7AlXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
然后在你的类中有 requre "~/twitter_auth.rb"
的地方,用这个替换(你还需要 require 'yaml'
在顶部文件):
@client = Twitter::Client.new(YAML.load_file("~/twitter_auth.yaml"))
I've written a simple Jekyll plugin to pull in my tweets using the twitter gem (see below). I'd like to keep the ruby script for the plugin on my open Github site, but following recent changes to the twitter API, the gem now requires authentication credentials.
require 'twitter' # Twitter API
require 'redcarpet' # Formatting links
module Jekyll
class TwitterFeed < Liquid::Tag
def initialize(tag_name, text, tokens)
super
input = text.split(/, */ )
@user = input[0]
@count = input[1]
if input[1] == nil
@count = 3
end
end
def render(context)
# Initialize a redcarpet markdown renderer to autolink urls
# Could use octokit instead to get GFM
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML,
:autolink => true,
:space_after_headers => true)
## Attempt to load credentials externally here:
require '~/.twitter_auth.rb'
out = "<ul>"
tweets = @client.user_timeline(@user)
for i in 0 ... @count.to_i
out = out + "<li>" + markdown.render(tweets[i].text) +
" <a href=\"http://twitter.com/" + @user + "/statuses/" +
tweets[i].id.to_s + "\">" + tweets[i].created_at.strftime("%I:%M %Y/%m/%d") +
"</a> " + "</li>"
end
out + "</ul>"
end
end
end
Liquid::Template.register_tag('twitter_feed', Jekyll::TwitterFeed)
If I replace the line
require '~/.twitter_auth.rb'
where twitter_auth.rb
contains something like:
require 'twitter'
@client = Twitter::Client.new(
:consumer_key => "CEoYXXXXXXXXXXX",
:consumer_secret => "apnHXXXXXXXXXXXXXXXXXXXXXXXX",
:oauth_token => "105XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
:oauth_token_secret => "BJ7AlXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
)
If I place these contents directly into the script above, then my plugin script works just fine. But when I move them to an external file and try to read them in as shown, Jekyll fails to authenticate. The function seems to work just fine when I call it from irb
, so I am not sure why it does not work during the Jekyll build.
I think that you may be confused about how require
works. When you call require
, first Ruby checks if the file has already been required, if so it just returns directly. If it hasn’t then the contents of the file are run, but not in the same scope as the require
statement. In other words using require
isn’t the same as replacing the require
statement with the contents of the file (which is how, for example, C’s #include
works).
In your case, when you require your ~/.twitter_auth.rb
file, the @client
instance variable is being created, but as an instance variable of the top level main
object, not as an instance variable of the TwitterFeed
instance where require
is being called form.
You could do something like assign the Twitter::Client
object to a constant that you could then reference from the render
method:
MyClient = Twitter::Client.new{...
and then
require '~/twitter_auth.rb'
@client = MyClient
...
I only suggest this as an explanation of what’s happening with require
, it’s not really a good technique.
A better option, I think, would be to keep your credentials in a simple data format in your home directory, then read them form your script and create the Twitter client with them. In this case Yaml would probably do the job.
First replace your ~/twitter_auth.rb
with a ~/twitter_auth.yaml
that looks soemthing like:
:consumer_key: "CEoYXXXXXXXXXXX"
:consumer_secret: "apnHXXXXXXXXXXXXXXXXXXXXXXXX"
:oauth_token: "105XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
:oauth_token_secret: "BJ7AlXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Then where you have requre "~/twitter_auth.rb"
in your class, replace with this (you’ll also need require 'yaml'
at the top of the file):
@client = Twitter::Client.new(YAML.load_file("~/twitter_auth.yaml"))