Which format should the version constant of my project have - ruby

Ive seen lots of stuff
Foo::VERSION::STRING
Foo::VERSION
Foo::Version
any suggestions what the best/most-common default is ?

First of all, Foo::Version seems wrong to me. That implicates that version is a Class or a Module, but should be a constant, as first two of your examples.
Apart from that, there is no golden rule here. Here are a few examples:
Rails:
Rails::VERSION::STRING
(Note: a module VERSION with all capitals.)
SimpleForm:
SimpleForm::VERSION
Nokogiri:
Nokogiri::VERSION
RSpec:
RSpec::Version::STRING
(Note, a module Version, compare with Rails above.)
Cucumber:
Cucumber::VERSION
SimpleForm:
SimpleForm::VERSION
Most of the above have their version defined in the lib/[name]/version.rb file, except for Rails, which has a version.rb in the root of the project, and Cucumber, which has buried it in the lib/cucumber/platform.rb file.
Also note that all of the above use Strings as a version. (Rails even concatenates MAJOR, MINOR, TINY, and PRE constants into a single VERSION constant.) This allows for easy comparison of versions:
"1.2.3" > "0.4.2" # => true
"1.2.3" > "1.2.2" # => true
"1.2.3" > "1.2" # => true
However, such a comparison fails when you run into double digits for the patch level:
"1.2.3" > "1.2.12" # => true
To me, defining Foo::VERSION is your best bet, define it in lib/foo/version.rb, and make it a String value.

Related

Loading unsafe YAMLs with YAML/Store in Psych 4

A recent change in Ruby's YAML Library (Psych 4) causes "unsafe" YAMLs to fail if they contain aliases, or try to instantiate unspecified classes. This is discussed in multiple places, like this StackOverflow question.
I am trying to figure out how to tell the derivative yaml/store library to allow loading unsafe YAMLs, or to provide it with my list of allowed classes.
The documentation is scarce as far as I could find, and after reading it, this is the only logical attempt I could come up with:
require 'date'
require 'yaml/store'
# 1. These options work perfectly with YAML.load_file, but not with YAML::Store
# 2. These options are not needed in Psych < 4.0
yaml_opts = { aliases: true, permitted_classes: [Time, Date, Symbol] }
store = YAML::Store.new 'log.yml', yaml_opts
data = store.transaction { store[:entries] }
p data
using this YAML file:
# log.yml
:entries:
- :timestamp: 2018-07-09 00:00:00.000000000 +03:00
:action: Comment
:comment: Started logging
This fails with Psych 4, and succeeds with Psych 3.
# Gemfile
source "https://rubygems.org"
gem 'psych', '>= 4.0' # fail
# gem 'psych', '< 4.0' # pass
As a related anecdote, the example demonstrated in the docs, also fails as-is when trying to load it with store.transaction { store["people"] }
Although this is not the proper way of doing things, until there is a better answer, I found that adding the below code fixes the problem.
module YAML
class << self
alias_method :load, :unsafe_load
end
end
This simply restores the underlying YAML::load method to its 3.x behavior of unsafe_load instead of safe_load.
In cases where my YAMLs come from a trusted source (100% of my use cases), I do not see any benefit in the new Psych 4 behavior, and feel it is ok (although awkward) to revert it.
The relevant source code reference is the 3.3.2 → 4.0.0 diff

Strange results for the Gem.latest_version_for(name) method

I am working on a gem related utility and I have observed strange results using Gem.latest_version_for method. Here are some observations under irb:
irb(main):001:0> Gem.latest_version_for('rails').to_s
=> "5.2.2"
irb(main):002:0> Gem.latest_version_for('gosu').to_s
=> "0.7.38"
Note how the first line, gets the correct version of rails, 5.2.2 as I write this and checking with rubygems.org confirms this. The query for the gosu gem returns 0.7.38 which is wildly wrong. The correct answer should be 0.14.4
I am at a loss to explain what is happening here.
I can confirm that my host is https://rubygems.org and
C:\Sites\mysh
8 mysh>ruby --version
ruby 2.3.3p222 (2016-11-21 revision 56859) [i386-mingw32]
C:\Sites\mysh
9 mysh>gem --version
2.5.2
The latest version available for i386-mingw32 platform is 0.7.38. You'll note this comports with what your ruby version is reported as.
https://rubygems.org/gems/gosu/versions
latest_version_for calls latest_spec_for, which calls Gem::SpecFetcher.spec_for_dependency with only the name of the gem as an argument. spec_for_dependency takes another argument, matching_platform, which defaults to true.
It looks like latest_version_for is scoped to your current platform thru that chain, with the matching_platform default. The gem install command might treat i386/x386 as the same/equivalent and allow them.
spec_for_dependency
if matching_platform is false, gems for all platforms are returned
You should be able to mirror the latest_spec_for method and pass in the multi_platform argument to override. Something like
dependency = Gem::Dependency.new name
fetcher = Gem::SpecFetcher.fetcher
spec_tuples, _ = fetcher.spec_for_dependency dependency, true # true added here
With the excellent help of Jay Dorsey, I think I have made some progress here. What I need to say is too large to fit in a comment and is the actual answer to the question about the odd behavior. Well at least I am pretty sure that it is.
As mentioned above: latest_version_for calls latest_spec_for, which calls Gem::SpecFetcher.spec_for_dependency.
The key is that that method then calls Gem::SpecFetcher.search_for_dependency. This is a long rambling method. I want to focus of one line that occurs after the specs have be obtained:
tuples = tuples.sort_by { |x| x[0] }
This sorts the tuples which are an array of [spec, source] arrays. It sorts them in ascending version/platform (as far as I can tell)
Now we return to the Gem class method latest_spec_for(name) and in particular the line:
spec, = spec_tuples.first
This grabs the first sub-array and keeps the spec and discards the source.
Note that it grabs the first element. The one with the lowest version number. This is normally not a problem because for the vast majority of gems, there will be only one spec present. Not so for the gosu gem. Here there are three due to the fact that gosu contains platform specific code. It seems to grab specs for the two Gem platforms ("ruby" and "x86-mingw32") and also the ruby platform (i386-mingw32).
To test my idea, I created the file glmp.rb (get last monkey patch) Here it is:
# The latest_spec_for(name) monkey patch.
module Gem
# Originally in File rubygems.rb at line 816
def self.latest_spec_for(name)
dependency = Gem::Dependency.new name
fetcher = Gem::SpecFetcher.fetcher
spec_tuples, = fetcher.spec_for_dependency dependency
spec_tuples[-1][0]
end
end
Now I know monkey patching is frowned upon, but for now this is just to test the idea. Here are my results:
36 mysh>=Gem.latest_version_for('gosu')
Gem::Version.new("0.7.38")
C:\Sites\ideas\gem_usage
37 mysh>ls
gem_latest.rb gem_usage.rb glmp.rb
C:\Sites\ideas\gem_usage
39 mysh>=require './glmp'
true
C:\Sites\ideas\gem_usage
40 mysh>=Gem.latest_version_for('gosu')
Gem::Version.new("0.14.4")
While I can use this hack to solve my problem for now, I think I will raise an issue with rubygems bringing up this matter.

Ohai thinks my plugin is version 6. Why?

I'm trying to write a plugin for ohai. It seems like a pretty straightforward task:
Ohai.plugin(:Uname) do
provides 'uname'
depends 'kernel'
collect_data do
uname Mash.new
uname[:message] = `uname -a`
end
end
To me this looks like the online examples provided by Opscode, O'Reilly and others. But here's what happens when I try to test it:
% irb -rohai
irb(main):001:0> Ohai::Config[:plugin_path] << "."
=> ["/home/ll0359/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/ohai-8.3.0/lib/ohai/plugins", "."]
irb(main):002:0> o = Ohai::System.new
=> #<Ohai::System:0x007fed82e43078 #plugin_path="", #data={}, #provides_map=#<Ohai::ProvidesMap:0x007fed82e42fd8 #map={}>, #v6_dependency_solver={}, #d82e42f38 #controller=#<Ohai::System:0x007fed82e43078 ...>, #v6_plugin_classes=[], #v7_plugin_classes=[]>, #runner=#<Ohai::Runner:0x007fed82e42ec0 #prp:0x007fed82e42fd8 #map={}>, #safe_run=true>>
irb(main):003:0> o.all_plugins
And here's where the fun begins. I get this output, over and over and over:
[2015-05-20T03:13:09+00:00] WARN: Plugin Definition Error: <./ohai_uname.rb>: collect_data already defined on platform default
[2015-05-20T03:13:09+00:00] WARN: [DEPRECATION] Plugin at ./test_ohai.rb is a version 6 plugin. Version 6 plugins will not be supported in future releases....
your plugin to version 7 plugin syntax. For more information visit here: docs.chef.io/ohai_custom.html
(the text on my second line was clipped by my screen but you get the idea)
I've tried running this code with and without the 'depends' line. Same result.
I've tried running this code with and without the Mash line, substituing 'uname uname -a' for the assignment line. Same result.
I've tried running with and without passing ":linux" as a parameter to collect_data. The only difference is I get a warning about collect_data(:linux) already being defined instead of :default.
I've tried renaming the plugin to a random 8 character identifier just in case it was tripping over being called :Uname. Same result.
I've tried passing "uname" (capital and lower) as a parameter to o.all_plugins. Same result.
So my questions are:
Why does ohai (8.3, running under Ruby 2.2.1) think this is a version 6 plugin? I can't see anything in it that would make it look like it's not version 7.
How can I get this working?
Thanks
Note to self: Next time you do this, don't try to test from the directory your plugin is in and add "." to your plugin_path. Moving to a different directory and adding the absolute path to the plugin solved the problem.
I plan to leave this up in case someone else has this happen to them.

Ruby/GSL online documentation for wrong version?

After successfuly installing Ruby/GSL library on my Debian (via *deb), with Ruby 1.9.3, I am having troubles running most of the GSL methods. Specifically, this webpage shows several code samples, but (in Arrays), right from the top line, require "GSL" is obsolete, it is require "gsl" today. The remaining methods also do not work.
For another example of my problem, consider another online reference to Ruby/GSL.
GSL::VERSION
#=> 1.15
GSL::pow_2( 4 )
#=> 16
But when I flip the page,
GSL::Complex.new( 0.9, 1.1 )
#=> ArgumentError: wrong number of arguments(2 for 0)
The simplest explanation to me would be that Ruby/GSL has more than one version hanging online, and the documentation I found is for the old one. For example, there is this abandoned version (https://github.com/codahale/ruby-gsl), so perhaps the version history is a bit complicated? Which is the authoritative version, and where can I finde the up-to-date documentation?
Following methods do work for the Complex module:
> c = GSL::Complex[0.9, 1.1]
=> GSL::Complex
[ 9.000e-01 1.100e+00 ]
> c.real
=> 0.9
> c.imag
=> 1.1
> c.pow 2
=> GSL::Complex
[ -4.000e-01 1.980e+00 ]

ArgumentError in YAML::dump if (what looks like a) date is invalid

Is there a way to make Psych a little dumber? If a string matches certain regular expression it tries to convert it to date and fails miserably. So far I switched to Syck for serializing but it's no longer maintained and I'm looking for better solution.
Here's an example of what's going on:
s = "2222-33-44" # => "2222-33-44"}
require 'yaml' # => true
YAML::dump s # ArgumentError: invalid date
YAML::ENGINE.yamler = 'syck' # => "syck"
YAML::dump s # => "--- \"2222-33-44\"\n"
I have found that it is a known bug. It has been fixed but looks like the version in RubyGems is not containing the fix.
Also as the git repository doesn't have a proper .gemspec is not easy way to install from the repo.
You can fork the repo and add a proper .gemspec and use a Gemfile that points to your fork repo.
Also you can ask kindly to Aaron to release the fix.

Resources