Ruby CLI报错:undefined method `title' for []:Array (NoMethodError)
解决你的Spotify榜单CLI工具错误&潜在问题排查
嘿,作为Ruby新手能写到这已经很棒了!咱们先把你卡了几小时的NoMethodError搞定,再一步步梳理其他隐藏问题:
1. 核心错误原因拆解
你遇到的undefined method 'title' for []:Array,本质是把数组当成单个Song对象来调用方法,具体坑点在这几个地方:
- 在
CLI#get_song里,你调用Topspotifysongs::Songs.get_song_details(input),但当前这个方法返回的是数组(collect的默认返回值),而且完全没用到传入的input参数; - 接着你把这个数组传给
show_song_details,然后调用song.title——数组哪来的title方法?自然就报错了。
2. 分步修复代码
第一步:重构Songs类的抓取与数据逻辑
当前的Songs.get_song_details既没正确抓取数据,也没初始化Song对象,咱们拆成两个方法:一个抓全量榜单,一个根据排名找单首歌:
class Topspotifysongs::Songs attr_accessor :title, :artist, :rank, :streams, :spotify_url @@all = [] def initialize(title=nil, artist=nil, rank=nil, streams=nil, spotify_url=nil) @title = title @artist = artist @rank = rank @streams = streams @spotify_url = spotify_url @@all << self end def self.all @@all end # 新增:抓取所有榜单歌曲并初始化Song对象 def self.scrape_all_songs require 'nokogiri' require 'open-uri' begin doc = Nokogiri::HTML(open("https://spotifycharts.com/regional")) # 修正CSS选择器:定位每一行歌曲的tr元素 doc.css("tbody tr").each do |row| # 提取标题:页面里标题在.chart-table-track下的strong标签 title = row.css(".chart-table-track strong").text.strip # 提取歌手:去掉"by "前缀 artist = row.css(".chart-table-track span").text.gsub("by ", "").strip # 提取排名并转成整数 rank = row.css(".chart-table-position").text.strip.to_i # 提取播放量 streams = row.css(".chart-table-streams").text.strip # 提取Spotify链接:a标签的href属性 spotify_url = row.css(".chart-table-image a").attr("href").value.strip # 初始化Song对象并存入@@all new(title, artist, rank, streams, spotify_url) end rescue OpenURI::HTTPError, SocketError => e puts "⚠️ 网络出错了:#{e.message}" exit end end # 修改:根据用户输入的排名返回单个Song对象 def self.get_song_details(target_rank) @@all.find { |song| song.rank == target_rank } end end
第二步:修正CLI类的交互逻辑
现在CLI需要先加载全量数据,再处理用户输入,还要兼容无效输入的情况:
class Topspotifysongs::CLI def start puts "正在加载Spotify全球榜单..." Topspotifysongs::Songs.scrape_all_songs puts "加载完成!请输入你想查看的歌曲排名(1-200):" get_song end def get_song input = gets.strip.to_i song = Topspotifysongs::Songs.get_song_details(input) if song # 歌曲存在则展示详情 puts "------------------------------------------------------------------------" show_song_details(song) puts "------------------------------------------------------------------------" else # 处理无效排名输入 puts "⚠️ 请输入1-200之间的有效数字哦!" end # 询问是否继续查询 puts "\nWould you like to show another song? (y/n)" repeat_or_done end def show_song_details(song) puts "----------- #{song.title} by #{song.artist} -----------" puts "" puts "Ranking: #{song.rank}" puts "" puts "Streams: #{song.streams}" puts "" puts "Link to song: #{song.spotify_url}" puts "" end def repeat_or_done input = gets.strip.downcase case input when "y" puts "\n请输入歌曲排名:" get_song when "n" puts "感谢使用!再见👋" else puts "请输入y或n哦!" repeat_or_done end end end
3. 其他潜在问题排查
依赖检查:确保你已经安装了
nokogiri,运行命令安装:gem install nokogiri(
open-uri是Ruby标准库,不需要额外安装)Scraper类的冗余:你代码里提到了
Topspotifysongs::Scraper但没实现,如果想把抓取逻辑拆分到单独的Scraper类,可以这么写:class Topspotifysongs::Scraper def self.scrape_chart_data require 'nokogiri' require 'open-uri' doc = Nokogiri::HTML(open("https://spotifycharts.com/regional")) doc.css("tbody tr").map do |row| { title: row.css(".chart-table-track strong").text.strip, artist: row.css(".chart-table-track span").text.gsub("by ", "").strip, rank: row.css(".chart-table-position").text.strip.to_i, streams: row.css(".chart-table-streams").text.strip, spotify_url: row.css(".chart-table-image a").attr("href").value.strip } end end end然后在Songs类的
scrape_all_songs里调用:def self.scrape_all_songs Topspotifysongs::Scraper.scrape_chart_data.each do |data| new(data[:title], data[:artist], data[:rank], data[:streams], data[:spotify_url]) end end测试启动:最后在入口文件里启动CLI即可:
Topspotifysongs::CLI.new.start
内容的提问来源于stack exchange,提问作者zachjohnson1
相关产品推荐
相关产品推荐

