Rubymine doesn't regonize shared context variables - ruby

I have specs that use variables from a shared context. The set up looks something like this:
shared_context.rb
RSpec.shared_context :handy_things do
let(:handy_object) { ... }
end
test_spec.rb:
require 'shared_context.rb'
describe 'Something happens' do
include_context :handy_things
before(:each) do
handy_object.option = true
end
...
The handy_object from the context is not recognized by Rubymine. I get an inspection message 'Cannot find...'.
This is not the end of the world but it annoys me.
Is there a way to let Rubymine know the variables of the shared context are accessible everywhere. Or as workaround to add my shared_context variables to some kind of dictionary so Rubymine doesn't flag it as unknown?

You might try two things:
Replacing your require with require_relative "shared_context" (with the relative path included if they're in different folders, no .rb extension necessary)
Specifying require "./shared_context"

Related

Problems with requiring files inside gem [duplicate]

What is the difference between require_relative and require in Ruby?
Just look at the docs:
require_relative complements the builtin method require by allowing you to load a file that is relative to the file containing the require_relative statement.
For example, if you have unit test classes in the "test" directory, and data for them under the test "test/data" directory, then you might use a line like this in a test case:
require_relative "data/customer_data_1"
require_relative is a convenient subset of require
require_relative('path')
equals:
require(File.expand_path('path', File.dirname(__FILE__)))
if __FILE__ is defined, or it raises LoadError otherwise.
This implies that:
require_relative 'a' and require_relative './a' require relative to the current file (__FILE__).
This is what you want to use when requiring inside your library, since you don't want the result to depend on the current directory of the caller.
eval('require_relative("a.rb")') raises LoadError because __FILE__ is not defined inside eval.
This is why you can't use require_relative in RSpec tests, which get evaled.
The following operations are only possible with require:
require './a.rb' requires relative to the current directory
require 'a.rb' uses the search path ($LOAD_PATH) to require. It does not find files relative to current directory or path.
This is not possible with require_relative because the docs say that path search only happens when "the filename does not resolve to an absolute path" (i.e. starts with / or ./ or ../), which is always the case for File.expand_path.
The following operation is possible with both, but you will want to use require as it is shorter and more efficient:
require '/a.rb' and require_relative '/a.rb' both require the absolute path.
Reading the source
When the docs are not clear, I recommend that you take a look at the sources (toggle source in the docs). In some cases, it helps to understand what is going on.
require:
VALUE rb_f_require(VALUE obj, VALUE fname) {
return rb_require_safe(fname, rb_safe_level());
}
require_relative:
VALUE rb_f_require_relative(VALUE obj, VALUE fname) {
VALUE base = rb_current_realfilepath();
if (NIL_P(base)) {
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
}
This allows us to conclude that
require_relative('path')
is the same as:
require(File.expand_path('path', File.dirname(__FILE__)))
because:
rb_file_absolute_path =~ File.expand_path
rb_file_dirname1 =~ File.dirname
rb_current_realfilepath =~ __FILE__
Summary
Use require for installed gems
Use require_relative for local files
require uses your $LOAD_PATH to find the files.
require_relative uses the current location of the file using the statement
require
Require relies on you having installed (e.g. gem install [package]) a package somewhere on your system for that functionality.
When using require you can use the "./" format for a file in the current directory, e.g. require "./my_file" but that is not a common or recommended practice and you should use require_relative instead.
require_relative
This simply means include the file 'relative to the location of the file with the require_relative statement'. I generally recommend that files should be "within" the current directory tree as opposed to "up", e.g. don't use
require_relative '../../../filename'
(up 3 directory levels) within the file system because that tends to create unnecessary and brittle dependencies. However in some cases if you are already 'deep' within a directory tree then "up and down" another directory tree branch may be necessary. More simply perhaps, don't use require_relative for files outside of this repository (assuming you are using git which is largely a de-facto standard at this point, late 2018).
Note that require_relative uses the current directory of the file with the require_relative statement (so not necessarily your current directory that you are using the command from). This keeps the require_relative path "stable" as it always be relative to the file requiring it in the same way.
From Ruby API:
require_relative complements the
builtin method require by allowing you
to load a file that is relative to the
file containing the require_relative
statement.
When you use require to load a file,
you are usually accessing
functionality that has been properly
installed, and made accessible, in
your system. require does not offer a
good solution for loading files within
the project’s code. This may be useful
during a development phase, for
accessing test data, or even for
accessing files that are "locked" away
inside a project, not intended for
outside use.
For example, if you have unit test
classes in the "test" directory, and
data for them under the test
"test/data" directory, then you might
use a line like this in a test case:
require_relative "data/customer_data_1"
Since neither
"test" nor "test/data" are likely to
be in Ruby’s library path (and for
good reason), a normal require won’t
find them. require_relative is a good
solution for this particular problem.
You may include or omit the extension
(.rb or .so) of the file you are
loading.
path must respond to to_str.
You can find the documentation at http://extensions.rubyforge.org/rdoc/classes/Kernel.html
The top answers are correct, but deeply technical. For those newer to Ruby:
require_relative will most likely be used to bring in code from another file that you wrote.
for example, what if you have data in ~/my-project/data.rb and you want to include that in ~/my-project/solution.rb? in solution.rb you would add require_relative 'data'.
it is important to note these files do not need to be in the same directory. require_relative '../../folder1/folder2/data' is also valid.
require will most likely be used to bring in code from a library someone else wrote.
for example, what if you want to use one of the helper functions provided in the active_support library? you'll need to install the gem with gem install activesupport and then in the file require 'active_support'.
require 'active_support/all'
"FooBar".underscore
Said differently--
require_relative requires a file specifically pointed to relative to the file that calls it.
require requires a file included in the $LOAD_PATH.
I just saw the RSpec's code has some comment on require_relative being O(1) constant and require being O(N) linear. So probably the difference is that require_relative is the preferred one than require.
I want to add that when using Windows you can use require './1.rb' if the script is run local or from a mapped network drive but when run from an UNC \\servername\sharename\folder path you need to use require_relative './1.rb'.
I don't mingle in the discussion which to use for other reasons.
absolute path
require './app/example_file.rb'
shortened name
require_relative 'example_file'

RubyMine: Unresolved Ruby Reference for global variable

Running RubyMine 2016.2.4. This project has a "global" singleton called $environment. All over the codebase this file is require_relative'd to get access to runtime dependencies. RubyMine is showing "Unresolved Ruby Reference" for every instance of $environment in classes which use this global.
Mock-up of how the environment.rb file looks:
require 'singleton'
class Environment
include Singleton
def log
...
end
end
$environment ||= Environment.instance
Example usage which RubyMine complains about:
require_relative '../environment'
class FancyWorker
def run
...
$environment.log.info 'Running!'
end
end
I've tried searching to no avail on how to resolve this inspection problem in RubyMine. I don't want to disable the inspection since it is useful for finding legitimate problems - but this is not a legitimate issue.
(Please keep commentary about globals being bad to yourself, I didn't make that design decision - I just want to help RubyMine understand the reference.)
I think you found a bug on RubyMine. Try changing:
$environment ||= Environment.instance
to:
$environment = $environment || Environment.instance
or just assign it if you're sure you won't be defining $environment anywhere else.

Testing Ruby-based CLIs with Aruba and Bundler

I have an RSpec suite, run via Bundler, that is testing a number of different command-line applications using Aruba. It works fine ... as long as the command being tested is not itself written in Ruby using Bundler. But I cannot figure out how to prevent the RSpec suite's bundler config from interfering with the execution of commands that themselves use Bundler - at least, not without extreme measures.
I have tried various permutations of unset_bundler_env_vars and with_clean_env, to no avail. Here's an example of a technique I thought would work:
describe 'my ruby app' do
before :each { unset_bundler_env_vars }
it 'should work' do
Bundler.with_clean_env { run_simple ruby_command_name }
end
end
I also tried unset_bundler_env_vars without with_clean_env, and vice-versa, in case they interfered with each other. No dice.
The only way I've gotten it to work is to massage Aruba's copy of the environment manually, like this:
before :all do
aruba.environment.tap do |env|
if env.include? 'BUNDLE_ORIG_PATH' then
env['PATH'] = env['BUNDLE_ORIG_PATH']
%w(BUNDLE_BIN_PATH BUNDLE_GEMFILE BUNDLE_ORIG_PATH GEM_HOME RBENV_DIR
RBENV_HOOK_PATH RUBYLIB RUBYOPT).each do |key|
env.delete key
end
end
end
end
There must be a better way. Neither the test suite nor the command being tested should know or care what language the other is written in. And my test code that uses Aruba and Bundler should not need to know the details of how bundle exec affects the process environment.
So what am I doing wrong? How should I be doing this?
It looks like unset_bundler_env_vars is deprecated and replaced by delete_by_environment_variable which requires a string param (source).
You might try before :each { delete_environment_variable('BUNDLE_GEMFILE') } in your spec. If that does not work, you may need to iterate through the PATH variable list to delete each one.
In the deprecation notice, there is a work-around, though I am not sure how brittle that would be moving forward.
unset_bundler_env_vars
aruba.environment.clear.update(ENV)
Hope this helps.

Rspec - Working directory

I have a class that laod config file from config/config.yml.
class Example
def initialize
config = YAML.load_file('config/config.yml')
end
end
I have created proyect/spec/config/config.yml example file but when I run the test it try load file proyect/config/config.yml.
How I change rspec working directory?
Why not point the config to the right path?
class Example
def initialize
config = YAML.load_file('spec/config/config.yml')
end
end
According to this, you can set the load_path like so
$LOAD_PATH.unshift 'spec'
or
$:.unshift 'spec'
Also according to that,
As much as I like removing unnecessary requires in specs I prefer verbosity over magic -- anything that gives the code reader more clarity as to what's necessary for a particular example group.

Using File::read in a provider's default.rb in Chef

I am trying to create an LWRP that will call the resource that is defined within itself. My cookbook's structure is as follows:
In the machine cookbook's provider, I have a code snippet as follows:
require 'chef/provisioning' # driver for creating machines
require '::File'
def get_environment_json
##environment_template = JSON.parse(File::read(new_resource.template_path + "environment.json"))
return ##environment_template
end
The code is only trying to read a json file and I am using File::read for it.
I keep getting an error as follows:
LoadError
cannot load such file -- ::File
Does anyone know how I can use File::read inside my LWRP's provider?
OK, so the prior two answers are both half right. You have two problems.
First, you can't require ::File as it's already part of Ruby. This is the cause of your error.
Second, if you call File.read you will grab Chef's File not ruby's. You need to do a ::File.read to use Ruby's File class.
require '::File'
Is incorrect and is causing the LoadError. Delete this line. You don't need it. File is part of the Ruby core and doesn't need to be required.
To further explain, the string argument to require represents the file name of the library you want to load. So, it should look like require "file", or require "rack/utils".
It happens becuase Chef already has a file resource. We have to use the Ruby File class in a recipe.We use ::File to use the Ruby File class to fix this issue. For example:
execute 'apt-get-update' do
command 'apt-get update'
ignore_failure true
only_if { apt_installed? }
not_if { ::File.exist?('/var/lib/apt/periodic/update-success-stamp') }
end
Source: https://docs.chef.io/ruby.html#ruby-class

Resources