Today I Learned Notes to self about software development

    Pushing gems to rubygems

    In your gem project run:

    rake build
    

    to create pkg/<gem-name>-0.1.0.gem

    Then run

    gem push pkg/<gem-name>-0.1.0.gem
    

    This should ask you to sign in, if you’re not already. Sign in credentials are stored in ~/.gem/credentials. So remove that if you want to “sign out” of rubygems.

    XCode Developer Cache

    In the eternal journey of freeing up more memory, I noticed that the storage management settings on my laptop (MacOS 12) had a new section for “developer cache”.

    xcode-cache.png

    (not actually my computer)

    Not only do I not know what is does, it also was taking up a lotta space!

    It turns out all of this “cache” is related to writing code for apple products which is not why I have xcode installed (I just need it for Ruby I think). So deleting the cache is safe to do, but it will keep coming back.

    To prevent that from happening, you need to open xcode (which actually made me install something else 😠) and delete all of the simulators.

    Menu > Window > Devices > Simulators

    then highlight and delete!

    Conditional Hash#merge

    I was in a situation where a key may or may not be present in a Hash (options), and I needed to do two different, but very similar things. The general if/else seemed like too much:

    if options[:uniqueness]
      if options[:scope]
        validates attribute, :uniqueness => { :case_sensitive => true, :scope => options[:scope] }
      else
        validates attribute, :uniqueness => { :case_sensitive => true }
      end
      # ...
    end
    

    So I found a nice one-liner that cleaned it up!

    if options[:uniqueness]
      uniqueness_options = {
        :case_sensitive => true,
        :scope => ( options[:scope] if options.has_key?(:scope))
      }.compact
    
      validates attribute, :uniqueness => uniqueness_options
    end
    

    Another approach was to use tap (which I need to lookup more about)

    { :a => 'animal' }.tap { |hash|
      hash[:b] = 'banana' if true
    }
    

    which maybe is better since it supports earlier Ruby version and is still very readable.

    Hash#merge and setting defaults

    When writing a method with an options Hash, how best do you specify default key/value pairs that can be safely overwritten?

    Well, if it’s just one this should be fine:

    def foo(k: 1)
      p k
    end
    
    foo({ k: 'apple'})
    

    but if you’re dealing with a double spat, Hash#merge is your friend.

    # Can also use a constant here to help document what the defaults are
    DEFAULTS = {
      fruit: 'apple',
      color: 'lavendar',
      feels: 'sleepy'
    }
    
    def blog(**options)
      options = DEFAULT.merge(options)
      # ...
    end
    

    merge works like this:

    h1 = { "a" => 100, "b" => 200 }
    h2 = { "b" => 254, "c" => 300 }
    h1.merge(h2)   #=> {"a"=>100, "b"=>254, "c"=>300}
    h1             #=> {"a"=>100, "b"=>200}
    

    prioritizing the values in the Hash argument.

    There’s also apparently Hash#reverse_merge in Rails, which handles duplicate values the other way— prioritizing the entries in the Hash calling the method.

    h1 = { "a" => 100, "b" => 200 }
    h2 = { "b" => 254, "c" => 300 }
    h1.reverse_merge(h2)   # => {"b"=>200, "c"=>300, "a"=>100} 
    

    gem cleanup

    This is a reminder to uninstall unused gems for each of the Ruby versions you have installed. Switch to the desired Ruby version and run

    gem cleanup
    

    This uninstalls unused versions of gems that are installed. I’m not sure how Ruby determines which gems are not in-use, but it’s handy because the different gem versions installed really add up. Run this command every few months. I don’t remember the last time I did this but I freed up like 3+GB of storage today just cleaning up gems.