How to call a method from a class inside the same module - crystal-lang

How do I call redis from a struct or a class?
module A::Cool::Module
redis = Redis.new(host: ENV["REDIS_DEV_HOST"], port: 18163)
redis.auth(ENV["REDIS_DEV_AUTH"])
struct CoolStruct
def CoolFunciton
redis # => undefined method 'redis' for A::Cool::Module:Module
end
end
end
I've tried the following without success
module A::Cool::Module
##redis = Redis.new(host: ENV["REDIS_DEV_HOST"], port: 18163)
##redis.auth(ENV["REDIS_DEV_AUTH"])
struct CoolStruct
def CoolFunciton
##redis # => can't infer the type of class variable '##redis'
end
end
end
module A::Cool::Module
module DB
redis = Redis.new(host: ENV["REDIS_DEV_HOST"], port: 18163)
redis.auth(ENV["REDIS_DEV_AUTH"])
end
struct CoolStruct
include A::Cool::Module::DB
def CoolFunciton
redis # => undefined local variable or method 'redis'
end
end
end
module A::Cool::Module
module DB
redis = Redis.new(host: ENV["REDIS_DEV_HOST"], port: 18163)
redis.auth(ENV["REDIS_DEV_AUTH"])
end
struct CoolStruct
include A::Cool::Module::DB
def CoolFunciton
A::Cool::Module::DB.redis # => undefined method 'redis'
end
end
end
I really have no idea how to do it.
And I don't want to create a redis connection for each class where I need redis.

Case is significant in Crystal. A module can have constants, which will be accessible throughout the module's scope (note the uppercase):
module A::Cool::Module
REDIS = ...
...
end
(Also, you should really use snake_case, not TitleCase for a method name; so cool_function, not CoolFunction.)

Related

How to use RuboCop::Cop::Rails::ApplicationRecord on Rails 4

I want to use ApplicationRecord Cop on Rails 4.
I already added 'self.abstract_class = true' .
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
And this file is written 'minimum_target_rails_version 5.0'.
https://github.com/rubocop-hq/rubocop-rails/blob/master/lib/rubocop/cop/rails/application_record.rb
So I created custom_cop like this.
# frozen_string_literal: true
module CustomCops
# #example
#
# # good
# class Rails5Model < ApplicationRecord
# # ...
# end
#
# # bad
# class Rails4Model < ActiveRecord::Base
# # ...
# end
class MustApplicationRecord < RuboCop::Cop::Cop
MSG = 'Models should subclass `ApplicationRecord`.'
SUPERCLASS = 'ApplicationRecord'
BASE_PATTERN = '(const (const nil? :ActiveRecord) :Base)'
include RuboCop::Cop::EnforceSuperclass
def autocorrect(node)
lambda do |corrector|
corrector.replace(node.source_range, self.class::SUPERCLASS)
end
end
end
end
But I got an error running rspec, like this.
Failure/Error:
class MustApplicationRecord < RuboCop::Cop::Cop
MSG = 'Models should subclass `ApplicationRecord`.'
SUPERCLASS = 'ApplicationRecord'
BASE_PATTERN = '(const (const nil? :ActiveRecord) :Base)'
include RuboCop::Cop::EnforceSuperclass
def autocorrect(node)
lambda do |corrector|
corrector.replace(node.source_range, self.class::SUPERCLASS)
NameError:
uninitialized constant CustomCops::RuboCop
Do you know how to solve this error, or other method( like override 'minimum_target_rails_version 5.0' to 'minimum_target_rails_version 4.0' ) ?
versions
Rails 4.2.8
ruby 2.6.6
rubocop 0.80.1
RSpec 3.9
The error is telling you that RuboCop is not defined.
You need to require 'rubocop' somewhere before you define your cop.

Rails `unitialized constant` for a constant defined in app/classes subdirectory in staging env

the error happens in :staging environment only
config/initializers/activity_api.rb:4:in 'block in <top (required)>'
Rails.application.config.to_prepare do
config = YAML.load_file('config/activity.yml')[Rails.env] || {}
config.deep_symbolize_keys!
Activity::API.config = config
end
And I have Activity::API class definition in app/classes/activity/api.rb
module Activity
class API
...
end
end
Shall I explicitely define a module Activity in app/classes/activity.rb and require files in app/classes/activity or there is something I misunderstand?
Maybe app/classes subdirectories are not in autoload path?
Creating an empty module Activity would help.
You can also try to user the inline class declaration style:
class Activity::Api
end

database_cleaner is wiping my development database

I have database-cleaner configured for my rails 4 application,
Each time I run the test, I discovered that my database gets wiped out in both the test and development environment.
My configurations are in rails_helper as follow:
ENV["RAILS_ENV"] ||= 'test'
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'database_cleaner'
Rails.env = "test"
# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.mock_with :rspec
config.before(:all) do
ActiveRecord::Base.skip_callbacks = true
end
config.after(:all) do
ActiveRecord::Base.skip_callbacks = false
end
end
How can I ensure that the cleaner only wipes the db in test environment without touching my development?
My database.yml is as follow:
# PostgreSQL. Versions 8.2 and up are supported.
#
# Install the pg driver:
# gem install pg
# On OS X with Homebrew:
# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On OS X with MacPorts:
# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem 'pg'
#
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: 5
development:
<<: *default
database: directory-service_development
# The specified database role being used to connect to postgres.
# To create additional roles in postgres see `$ createuser --help`.
# When left blank, postgres will use the default role. This is
# the same name as the operating system user that initialized the database.
#username: directory-service
# The password associated with the postgres role (username).
#password:
# Connect on a TCP socket. Omitted by default since the client uses a
# domain socket that doesn't need configuration. Windows does not have
# domain sockets, so uncomment these lines.
#host: localhost
# The TCP port the server listens on. Defaults to 5432.
# If your server runs on a different port number, change accordingly.
#port: 5432
# Schema search path. The server defaults to $user,public
#schema_search_path: myapp,sharedapp,public
# Minimum log levels, in increasing order:
# debug5, debug4, debug3, debug2, debug1,
# log, notice, warning, error, fatal, and panic
# Defaults to warning.
#min_messages: notice
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: directory-service_test
# As with config/secrets.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="postgres://myuser:mypass#localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%= ENV['DATABASE_URL'] %>
#
production:
<<: *default
database: directory-service_production
username: directory-service
password: <%= ENV['DIRECTORY-SERVICE_DATABASE_PASSWORD'] %>
I'd recommend changing
ENV["RAILS_ENV"] ||= 'test'
to
ENV["RAILS_ENV"] = 'test'
and remove
Rails.env = 'test'
as the RAILS_ENV environment variable should be sufficient for configuration
If anyone is looking for another potential source of this issue, I randomly had $DATABASE_URL defined in my .bashrc file to point directly to my development database. Took me a few hours to find that.
In my case it was database connection specified in .env file when I used dotenv-rails gem. For some reasons database_cleaner prefer connection from there instead of rails application config.
Well, I'm not sure what I was doing wrong, but by undoing all the configurations I had for database_cleaner:
uninstalling the database_cleaner gem
removing all related configurations from both spec_helper and rails_helper
And then following this guide by Avdi Grimm, after re-installing the database_cleaner gem and also uncomment this line:
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
from my rails_helper, I was able to get the database_cleaner back to work as expected. Thank you all.
I appreciate this is an old post but I had this issue today.
I checked using pry and my
ENV['RAILS_ENV'] = 'test' however my ENV['DATABASE_URL'] was set to my development db in the form of:
postgres://localhost/my_dev_db
I added a line in the database cleaner config in rails_helper.rb to change to my test db like so:
config.before(:suite) do
ActiveRecord::Base.establish_connection(ENV['DATABASE_TEST'])
DatabaseCleaner.clean_with(:truncation)
end
where ENV['DATABASE_TEST'] was in the form of:
postgres://localhost/my_test_db
This solved the issue for me.
For me the issue was having DatabaseCleaner.clean on the top level of rails_helper instead of within config.before(:suite).

Rails: changing from development to production leads to NameError uninitialized constant

My application works in dev environment (WEBrick 1.3.1) on my mac laptop. I deployed it via capistrano onto a Ubuntu server running nginx & passenger and suddenly I am getting
NameError in SmsController#send_text_message: uninitialized constant
SmsController::PhoneNumber
. Here is a screenshot:
Apparently, the PhoneNumber class (app/models/phone_number.rb) is not being recognized. Here is the code for that class:
class PhoneNumber
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :pnumber
validates :pnumber, presence: true
validates :pnumber, numericality: true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
Here is the code for the controller where the error is raised:
class SmsController < ApplicationController
def send_text_message
phone = PhoneNumber.new(pnumber: params[:phone])
logger.info "phone as submitted by the webform (params[:phone]) = " + params[:phone]
if phone.valid?
# code that sends a sms message..
flash[:success] = "Message has been sent!"
redirect_to :back
else
flash[:warning] = "This is not a valid mobile number"
redirect_to :back
end
end
end
What do I need to do to make this work in production?
==EDIT: I ran it locally on my mac under the production environment using the same stack (nginx, passenger) and I am not getting the error message. So it seems it must be something specific to the installation on my Ubuntu VPS. I re-started nginx but it did not change anything. I am really stumped - in theory this quirk should not happen.
==EDIT2: As requested by #rossta here is the content of config/application.rb:
require File.expand_path('../boot', __FILE__)
# Pick the frameworks you want:
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "sprockets/railtie"
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Appmate
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
end
end
And here is the content of config/environments/production.rb:
Appmate::Application.configure do
config.cache_classes = true a
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = true # changed to help with debugging, TODO: change back to false once in production
config.action_controller.perform_caching = true
# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
# config.action_dispatch.rack_cache = true
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Generate digests for assets URLs.
config.assets.digest = true
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
config.log_level = :info
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Disable automatic flushing of the log to improve performance.
# config.autoflush_log = false
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
end
I found the culprit - I seem to have not committed to my git repository the controller and the model files. So everything was working apart from that bit. Duh!
#rossta: thanks for helping! That stray 'a' is something that I must have added while copying the code into the SO post but your question made me look into my git repository - and this is how I found the changed but uncommitted files.

How can I use Sinatra to simulate a remote server in RSpec / VCR?

The VCR Cucumber documents show many examples using a tiny Sinatra app to simulate a remote server, using a function called start_sinatra_app loaded from vcr_cucumber_helpers.rb.
I'd like use something like that for my Rails / RSpec / VCR testing, but haven't figured out how to get start_sinatra_app (or equivalent) into my testing framework. My naive approach doesn't work since -- not surprisingly -- it can't find vcr_cucumber_helpers.rb.
What do I need to add to the following to make it work under RSpec? Or am I off in the weeds and doing this all wrong?
# file: spec/app/models/sinatra_test_spec.rb
require 'spec_helper'
start_sinatra_app(:port => 7777) do
get("/") { "Hello" }
end
describe "sinatra rspec test" do
it 'calls the sinatra app' do
VCR.use_cassette("sinatra_rspec_test") do
res = Net::HTTP.get_response('localhost', "/", 7777)
res.body.should == 'Hello'
end
end
end
Here's the code you're looking for:
def start_sinatra_app(options, &block)
raise ArgumentError.new("You must pass a port") unless options[:port]
require 'sinatra'
require 'support/vcr_localhost_server'
klass = Class.new(Sinatra::Base)
klass.disable :protection
klass.class_eval(&block)
VCR::LocalhostServer.new(klass.new, options[:port])
end
That in turn uses VCR::LocalhostServer:
require 'rack'
require 'rack/handler/webrick'
require 'net/http'
# The code for this is inspired by Capybara's server:
# http://github.com/jnicklas/capybara/blob/0.3.9/lib/capybara/server.rb
module VCR
class LocalhostServer
READY_MESSAGE = "VCR server ready"
class Identify
def initialize(app)
#app = app
end
def call(env)
if env["PATH_INFO"] == "/__identify__"
[200, {}, [VCR::LocalhostServer::READY_MESSAGE]]
else
#app.call(env)
end
end
end
attr_reader :port
def initialize(rack_app, port = nil)
#port = port || find_available_port
#rack_app = rack_app
concurrently { boot }
wait_until(10, "Boot failed.") { booted? }
end
private
def find_available_port
server = TCPServer.new('127.0.0.1', 0)
server.addr[1]
ensure
server.close if server
end
def boot
# Use WEBrick since it's part of the ruby standard library and is available on all ruby interpreters.
options = { :Port => port }
options.merge!(:AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new)) unless ENV['VERBOSE_SERVER']
Rack::Handler::WEBrick.run(Identify.new(#rack_app), options)
end
def booted?
res = ::Net::HTTP.get_response("localhost", '/__identify__', port)
if res.is_a?(::Net::HTTPSuccess) or res.is_a?(::Net::HTTPRedirection)
return res.body == READY_MESSAGE
end
rescue Errno::ECONNREFUSED, Errno::EBADF
return false
end
def concurrently
# JRuby doesn't support forking.
# Rubinius does, but there's a weird issue with the booted? check not working,
# so we're just using a thread for now.
Thread.new { yield }
end
def wait_until(timeout, error_message, &block)
start_time = Time.now
while true
return if yield
raise TimeoutError.new(error_message) if (Time.now - start_time) > timeout
sleep(0.05)
end
end
end
end
Webmock does this quite nicely.
Allow connections to localhost:
# spec/spec_helper.rb
require 'webmock/rspec'
WebMock.disable_net_connect!(allow_localhost: true)
And then point your URL to the app:
# spec/spec_helper.rb
RSpec.configure do |config|
config.before(:each) do
stub_request(:any, /api.github.com/).to_rack(SinatraApp)
end
end
For a clearer example, see:
http://robots.thoughtbot.com/how-to-stub-external-services-in-tests