Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Ruby mixin模块的规格有问题_Ruby On Rails_Ruby_Rspec_Module - Fatal编程技术网

Ruby on rails Ruby mixin模块的规格有问题

Ruby on rails Ruby mixin模块的规格有问题,ruby-on-rails,ruby,rspec,module,Ruby On Rails,Ruby,Rspec,Module,我对mixin模块没有很好的经验。那么,如果我的问题有点天真,请原谅我 我正在创建几个模块,将一个项目与音乐服务(如Spotify)集成,后者拥有REST API。所有这些模块都包括我创建的另一个名为APIClientBuilder的mixin模块,它提供了一个用于创建API端点的小型DSL lib/integrations/api\u client\u builder.rb require 'rest-client' module APIClientBuilder attr_acces

我对mixin模块没有很好的经验。那么,如果我的问题有点天真,请原谅我

我正在创建几个模块,将一个项目与音乐服务(如Spotify)集成,后者拥有REST API。所有这些模块都包括我创建的另一个名为APIClientBuilder的mixin模块,它提供了一个用于创建API端点的小型DSL

lib/integrations/api\u client\u builder.rb

require 'rest-client'

module APIClientBuilder

  attr_accessor :api_client, :endpoint, :url, :param

  def api_client(api_name)
  end

  def fetch_client(api_name)
  end

  def api_endpoint(endpoint_name)
  end

  def fetch_endpoint(api_name,endpoint_name)
  end 

  def method=(meth)
  end   

  def url=(endpoint_url) 
  end

  def param(param_name,param_value)
  end

  def call(api_name,api_endpoint,token,*extra_params)
  end

end
require_relative 'api_client_builder'

module SpotifyIntegration

  include APIClientBuilder

  def base_url
    'https://api.spotify.com/v1'
  end

  def random_state_string
    (0..10).map { (65 + rand(26)).chr }.join
  end

  api_client('spotify') do |apic|

    apic.api_endpoint('request_authorization') do |ep|
      ep.method = :get
      ep.url = "https://accounts.spotify.com/authorize"
      ep.param("client_id",SPOTIFY_KEY)
      ep.param("response_type","code")
      ep.param("redirect_uri","http://localhost:3000")
    end

    apic.api_endpoint('my_playlists') do |ep|
      ep.method = :get
      ep.url = "#{base_url}/me/playlists"
    end

  end

end
require 'integrations/spotify.rb'

class UsersController < ApplicationController

  include SpotifyIntegration

end
require 'rails_helper'

require 'integrations/spotify'

class SpotifyClientTester
  include SpotifyIntegration
end

RSpec.describe SpotifyIntegration do

  context 'Auxiliary methods' do

    it 'Two calls to random_state_string shall generate two different strings' do
      obj = SpotifyClientTester.new
      s1 = obj.random_state_string
      s2 = obj.random_state_string
      expect(s1).not_to eq(s2)
    end

  end

end
lib/integrations/spotify.rb

require 'rest-client'

module APIClientBuilder

  attr_accessor :api_client, :endpoint, :url, :param

  def api_client(api_name)
  end

  def fetch_client(api_name)
  end

  def api_endpoint(endpoint_name)
  end

  def fetch_endpoint(api_name,endpoint_name)
  end 

  def method=(meth)
  end   

  def url=(endpoint_url) 
  end

  def param(param_name,param_value)
  end

  def call(api_name,api_endpoint,token,*extra_params)
  end

end
require_relative 'api_client_builder'

module SpotifyIntegration

  include APIClientBuilder

  def base_url
    'https://api.spotify.com/v1'
  end

  def random_state_string
    (0..10).map { (65 + rand(26)).chr }.join
  end

  api_client('spotify') do |apic|

    apic.api_endpoint('request_authorization') do |ep|
      ep.method = :get
      ep.url = "https://accounts.spotify.com/authorize"
      ep.param("client_id",SPOTIFY_KEY)
      ep.param("response_type","code")
      ep.param("redirect_uri","http://localhost:3000")
    end

    apic.api_endpoint('my_playlists') do |ep|
      ep.method = :get
      ep.url = "#{base_url}/me/playlists"
    end

  end

end
require 'integrations/spotify.rb'

class UsersController < ApplicationController

  include SpotifyIntegration

end
require 'rails_helper'

require 'integrations/spotify'

class SpotifyClientTester
  include SpotifyIntegration
end

RSpec.describe SpotifyIntegration do

  context 'Auxiliary methods' do

    it 'Two calls to random_state_string shall generate two different strings' do
      obj = SpotifyClientTester.new
      s1 = obj.random_state_string
      s2 = obj.random_state_string
      expect(s1).not_to eq(s2)
    end

  end

end
我的想法是在我的控制器里有这样的东西:

app/controllers/api/v1/users\u controller.rb

require 'rest-client'

module APIClientBuilder

  attr_accessor :api_client, :endpoint, :url, :param

  def api_client(api_name)
  end

  def fetch_client(api_name)
  end

  def api_endpoint(endpoint_name)
  end

  def fetch_endpoint(api_name,endpoint_name)
  end 

  def method=(meth)
  end   

  def url=(endpoint_url) 
  end

  def param(param_name,param_value)
  end

  def call(api_name,api_endpoint,token,*extra_params)
  end

end
require_relative 'api_client_builder'

module SpotifyIntegration

  include APIClientBuilder

  def base_url
    'https://api.spotify.com/v1'
  end

  def random_state_string
    (0..10).map { (65 + rand(26)).chr }.join
  end

  api_client('spotify') do |apic|

    apic.api_endpoint('request_authorization') do |ep|
      ep.method = :get
      ep.url = "https://accounts.spotify.com/authorize"
      ep.param("client_id",SPOTIFY_KEY)
      ep.param("response_type","code")
      ep.param("redirect_uri","http://localhost:3000")
    end

    apic.api_endpoint('my_playlists') do |ep|
      ep.method = :get
      ep.url = "#{base_url}/me/playlists"
    end

  end

end
require 'integrations/spotify.rb'

class UsersController < ApplicationController

  include SpotifyIntegration

end
require 'rails_helper'

require 'integrations/spotify'

class SpotifyClientTester
  include SpotifyIntegration
end

RSpec.describe SpotifyIntegration do

  context 'Auxiliary methods' do

    it 'Two calls to random_state_string shall generate two different strings' do
      obj = SpotifyClientTester.new
      s1 = obj.random_state_string
      s2 = obj.random_state_string
      expect(s1).not_to eq(s2)
    end

  end

end
但当我运行它时,我得到了

未定义的本地变量或方法
base\u url
用于SpotifyIntegration:Module(nameferror)

我不确定我错过了什么。也许我应该使用
extend
而不是
include
。我总是对此感到困惑


有人能帮我找到正确的路吗?我已经与这个错误斗争了整整一个下午。

如果您想使用在模块
SpotifyIntegration
的类级别定义的方法,您需要扩展
APIClientBuilder

module SpotifyIntegration

  extend APIClientBuilder

另外,
base\u url
也必须是一个类方法,
def self.base\u url
如果要使用在模块
SpotifyIntegration
的类级别定义的方法,则需要扩展
APIClientBuilder

module SpotifyIntegration

  extend APIClientBuilder

另外,
base\u url
也必须是类方法,
def self.base\u url

您误用了mixin。对于经典继承不适合向对象添加一组特征的情况,请使用mixin

例如:

module Commentable
  extend ActiveSupport::Concern

  included do
    has_many :comments, as: :commentable
  end 
  # ...
end

class Video < ApplicationRecord
  include Commentable
end

class Hotel < ApplicationRecord
  include Commentable
end

为什么不将API客户机混合到控制器或模型中?因为单一责任原则和事实,使用较小的部分来做有限的事情比创建上帝类更可取

你误用了mixin。对于经典继承不适合向对象添加一组特征的情况,请使用mixin

例如:

module Commentable
  extend ActiveSupport::Concern

  included do
    has_many :comments, as: :commentable
  end 
  # ...
end

class Video < ApplicationRecord
  include Commentable
end

class Hotel < ApplicationRecord
  include Commentable
end

为什么不将API客户机混合到控制器或模型中?因为单一责任原则和事实,使用较小的部分来做有限的事情比创建上帝类更可取

它在哪一条线上失败了?您甚至没有在测试中调用
base\u url
方法,而且
random\u state\u string
也没有调用
base\u url
lib/integrations/spotify.rb:33
,这表示
ep.url=“{base\u url}/me/playlists”
。你说的正是我最困惑的地方。我甚至不调用
base\u url
。这不在这篇文章的片段中,
ep.url=“{base\u url}/me/playlists”
。抱歉,我现在编辑了它。我错误地删除了这个部分。这是在班级层面上的原因吗?api|U客户端(“spotify”)do | apic |----------在哪一行发生故障?您甚至没有在测试中调用
base\u url
方法,而且
random\u state\u string
也没有调用
base\u url
lib/integrations/spotify.rb:33
,这表示
ep.url=“{base\u url}/me/playlists”
。你说的正是我最困惑的地方。我甚至不调用
base\u url
。这不在这篇文章的片段中,
ep.url=“{base\u url}/me/playlists”
。抱歉,我现在编辑了它。我错误地删除了这个部分。这是在班级层面上的原因吗?api_client(“spotify”)do | apic |------------------在
SpotifyIntegration
中扩展它?在
SpotifyIntegration
中扩展它?是的,如果您不打算创建它的实例,客户端可以是一个模块。但在大多数情况下,您希望将客户机和服务对象设置为类,以便更容易通过初始值设定项注入配置。是的,如果您不打算创建其实例,则客户机可以是一个模块。但在大多数情况下,您希望将客户机和服务对象设置为类,以便更容易通过初始值设定项注入配置。