ShakaCode | ShakaCode Blog | Rails On Maui Blog | Rails | ReactJs | JavaScript | Webpack | Productivity |

Yak of the week! Ruby 2.4 Pathname empty? changed to look at file size!


#1

Yak of the week! Ruby 2.4 Pathname empty? changed to look at file size!

Pathname.present? is false for existing file with empty contents! and a good example of Pry saving me!

I had failing tests in React on Rails due Ruby 2.4.1 due to a change in the Pathname API. Previously, for Ruby 2.3, Pathname.empty? would return false if the file’s name is not empty, not the contents!

[43] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.blank?
true
[44] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.to_s
"/var/folders/rp/_k99k0pn0rsb4d3lm9l3dnjh0000gn/T/d20170603-96466-zk7di7"
[45] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.present?
false
[58] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.presence
nil

WTF?

[59] (pry) #<ReactOnRails::AssetsPrecompile>: 0> $ assets_path.presence

From: /Users/justin/.rvm/gems/ruby-2.4.1@react_on_rails/gems/activesupport-5.1.1/lib/active_support/core_ext/object/blank.rb @ line 43:
Owner: Object
Visibility: public
Number of lines: 3

def presence
  self if present?
end
[60] (pry) #<ReactOnRails::AssetsPrecompile>: 0> $ assets_path.present?

From: /Users/justin/.rvm/gems/ruby-2.4.1@react_on_rails/gems/activesupport-5.1.1/lib/active_support/core_ext/object/blank.rb @ line 23:
Owner: Object
Visibility: public
Number of lines: 3

def present?
  !blank?
end
[46] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.nil?
false
[52] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.exist?
true
[53] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.blank?
true

WTF!!!

The file exists, but blank? is true.

[54] (pry) #<ReactOnRails::AssetsPrecompile>: 0> $ assets_path.blank?

From: /Users/justin/.rvm/gems/ruby-2.4.1@react_on_rails/gems/activesupport-5.1.1/lib/active_support/core_ext/object/blank.rb @ line 16:
Owner: Object
Visibility: public
Number of lines: 3

def blank?
  respond_to?(:empty?) ? !!empty? : !self
end
[55] (pry) #<ReactOnRails::AssetsPrecompile>: 0> $ assets_path.empty?

From: ext/pathname/pathname.c (C Method):
Owner: Pathname
Visibility: public
Number of lines: 10

static VALUE
path_empty_p(VALUE self)
{

    VALUE path = get_strpath(self);
    if (RTEST(rb_funcall(rb_mFileTest, rb_intern("directory?"), 1, path)))
        return rb_funcall(rb_cDir, rb_intern("empty?"), 1, path);
    else
        return rb_funcall(rb_mFileTest, rb_intern("empty?"), 1, path);
}
[56] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.empty?
true
[57] (pry) #<ReactOnRails::AssetsPrecompile>: 0> assets_path.class
Pathname < Object

The reason why is that empty? is true!

These are my pry shortcuts! Pry is so useful!

See My .pryrc for debugging and productivity

Debugging Shortcuts
ss  :  step
nn  :  next
cc  :  continue
fin :  finish
uu  :  up
dd  :  down
bb  :  break
ww  :  whereami
ff  :  frame
sss :  show-stack
$   :  show whole method of context

Run 'pry_debug' or 'pd' to display shorter debug shortcuts

Utility method to solve the problem with tests

Utils.rb

module ReactOnRails
  module Utils
      # https://forum.shakacode.com/t/yak-of-the-week-ruby-2-4-pathname-empty-changed-to-look-at-file-size/901
    # return object if truthy, else return nil
    def self.truthy_presence(obj)
      if obj.nil? || obj == false
        nil
      else
        obj
      end
    end
end

Tests

module ReactOnRails
  RSpec.describe Utils do
    describe ".truthy_presence" do
      context "With non-empty string" do
        subject { "foobar" }
        it "returns subject (same value as presence) for a non-empty string" do
          expect(Utils.truthy_presence(subject)).to eq(subject.presence)

          # Blank strings are nil for presence
          expect(Utils.truthy_presence(subject)).to eq(subject)
        end
      end

      context "With empty string" do
        subject { "" }
        it "returns \"\" for an empty string" do
          expect(Utils.truthy_presence(subject)).to eq(subject)
        end
      end

      context "With nil object" do
        subject { nil }
        it "returns nil (same value as presence)" do
          expect(Utils.truthy_presence(subject)).to eq(subject.presence)

          # Blank strings are nil for presence
          expect(Utils.truthy_presence(subject)).to eq(nil)
        end
      end

      context "With pathname pointing to empty dir (obj.empty? is true)" do
        subject(:empty_dir) { Pathname.new(Dir.mktmpdir) }
        it "returns Pathname object" do
          # Blank strings are nil for presence
          expect(Utils.truthy_presence(empty_dir)).to eq(empty_dir)
        end
      end

      context "With pathname pointing to empty file" do
        let(:empty_dir) { Pathname.new(Dir.mktmpdir) }
        subject(:empty_file) { File.basename(Tempfile.new("tempfile",
                                                          empty_dir)) }
        it "returns Pathname object" do
          expect(Utils.truthy_presence(empty_file)).to eq(empty_file)
        end
      end
    end
  end
end