Ruby
Useful Resources
- Gemfile of Dreams - The Libraries Evil Martians Use to Build Rails Apps
- Using Zeitwerk Outside Rails - Zeitwerk is a thread-safe Ruby code loader supporting both autoloading and eager loading. It’s commonly associated with Rails, but can be used without it too.
- Railway design
- Dry Monads - Very interesting and popular concept of
dry
in Ruby, however it adds a substantial mental strain when working with Rails concepts as you need to switch between them / see the difference. - Graceful Dev Avdi Grim with a lot of high quality free and paid content
Articles
blog has information on why to prefer accessing instance variables via attribute methods.
TODO
irb --simple-prompt
Debugging
if $PROGRAM_NAME == __FILE__
binding.irb if $DEBUG
end
ruby -d series.rb #
# or
ruby --disable-gems -d series.rb
load script into irb session(instead of adding binding at the EOF)
irb --simple-prompt -r ./series.rb
RDBG
bundle exec rdbg -c -- bundle exec rspec spec/worker_integrations/async_jobs/events/create_customer_order_from_external_order_updated_event_integration_spec.rb:57
b ActiveRecord::Associations::SingularAssociation#build
? b # RTFM
c # continue
i # info
s # step
f 1 # step back? frame command
del 0 # delete breakpoint
l # list, similar whereami?
finish
class instance vars
class Lala
def self.lala
@hey ||= Time.now
end
end
Lala.lala
14:17:21.110873 +1000
Lala.lala
14:17:21.110873 +1000
Load Path
$LOAD_PATH.unshift(File.join(__dir__, 'lib'))
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
Case pattern matching
case input
in "lala" then puts 'yolo'
in [_,a] if true
puts a #=> 2
in _ => anything_else_reassigned
puts anything_else_reassigned
end
Rails Resources
- Advanced Active Record Concepts - A tour of concepts including locking records to avoid conflicts, using UUIDs as primary keys, fulltext search, using database views, and working with geospatial data. I suspect it might end up with a 2024 update for vector similarity queries.. 😁
- Split your database seeds.rb by Rails environment
Tools
- An OpenAI API client.
- twilio-ruby
- Bullet Train Rails Template
- rails-brotli-cache
- rspec-sidekiq
- deep_pluck - Pluck deeply into nested associations without loading a bunch of records.
Gems
Cleaning up
gem pristine --all
gem cleanup
- Gemfile of Dreams - The Libraries Evil Martians Use to Build Rails Apps
Scheduling
https://github.com/jjb/ruby-clock - ruby clock (for simple tasks)
Money
257.78 * 100
#=> 25777.999999999996
289.15 * 100
#=> 28914.999999999996
require "bigdecimal"
"%2.2f" % (BigDecimal('289.15') * BigDecimal(100))
#=> "28915.00"
https://www.honeybadger.io/blog/ruby-currency/
Ruby
assessment_type&.name
# OR
assessment_type.try(:name) # ------> RAILS verion
ARGS forwarding
def concrete_method(*positional_args, **keyword_args, &block)
positional_args
keyword_args
block.call
end
def forwarding_method(...)
concrete_method(...)
end
concrete_method(1, b: 2) { puts 3 }
All class methods
self.class.instance_methods(false)
.each { |m| self.send m }
UUID
Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, "fresho_salmon_heads")
Rails
init new project
rails new myapp \
--minimal \
--database=postgresql
Search all database
ApplicationRecord.descendants.map {|m| m.all }
Ignore columns on load
self.ignored_columns += %w[some_id]
Rails Logging switching via console
Rails.logger.level = :debug
Rake
https://github.com/friendlyantz/rake-sandbox
Inline execution
ruby -e puts 'Hello, world!'
rake -e puts 'Hello, world!'
File writing
%W[ch1.md ch2.md ch3.md].each do |md_file|
html_file = File.basename(md_file, ".md") + ".html"
file html_file => md_file do
sh "pandoc -o #{html_file} #{md_file}"
end
end
I had to call with .html
, not .md
, which was a bit confusing.
Now rake handles file writing and trackes if there are any updates in .md
file worth calling a conversion operation
❯ rake md_to_html README.html
pandoc -o README.html README.md
❯ rake md_to_html README.html
❯ rake md_to_html README.html
using Rules
unlike previous commit this rule defines a saving
RULE for files with .html extension with prerequisite ‘md’ file, so the
rake initially looks for a rule with exact match of README.html
, doesn’t
find and then goes to generic ‘.html’ rule
Previously with used file
task, with explicit name of the file
rule '.html' => '.md' do |t|
if `which pandoc`.empty?
puts 'pandoc is not installed'
exit 1
end
sh "pandoc -o #{t.name} #{t.source}"
end
Listing files
files = Rake::FileList['**/*.md']
files.exclude('**/~*') # exclude files with ~ in the name
files.exclude do |file|
`git ls-files #{file}`.empty? # exclude files that are not tracked by git
end
files.exclude /^ignoredir/ # using REGEX
OR create instance of a file list and pass a block
files = Rake::FileList.new('**/*.md') do |fl|
fl.exclude('**/~*') # exclude files with ~ in the name
fl.exclude do |file|
`git ls-files #{file}`.empty? # exclude files that are not tracked by git
end
fl.exclude(/^ignoredir/) # using REGEX
fl.exclude(/README/) # using REGEX
end
listing files with new file ext
files.ext('html')
Exercism takeaways
GitHub exercism/ruby solutions with some comments in commit Interesting exercises:
- Two Fer
- Resistor Color Duo
class
vs instance
methods
The class level method is there for convenience only, and it should stay inflexible, as it is there for convenience not power. We will see this decision in use in our “expansion”, below.
Hash freezing and I18N connection
The languages available and the translations available should be a single thing, a Hash. Otherwise there more of a chance that things can become disconnected in the way that they are now related, (but not connected).
then
as a circuit breaker
# meets condition, no-op
1.then.detect(&:odd?) # => 1
# does not meet condition, drop value
2.then.detect(&:odd?) # => nil
Progress Bar with custom style
bundle add progressbar
require 'progressbar'
progressbar = ProgressBar.create(
total: Ladida.count,
format: "%a %e %P% %b\u{15E7}%i RateOfChange: %r Processed: %c from %C",
progress_mark: " ",
remainder_mark: "\u{FF65}",
)
# in loop just do
progressbar.increment
# with colorize
require 'colorize'
progressbar = ProgressBar.create(
total: range.count,
format: "%a %e %P% %b#{"\u{15E7}".yellow}%i RateOfChange: %r Processed: %c from %C",
progress_mark: ' ',
remainder_mark: "\u{FF65}".light_green
)
docs https://github.com/jfelchner/ruby-progressbar/wiki/Formatting
CSV + AWS S3
require "csv"
require "aws-sdk-s3"
s3 = Aws::S3::Client.new(
region: "ap-southeast-2",
credentials: Aws::Credentials.new(
ENV.fetch("AWS_ACCESS_KEY_ID"),
ENV.fetch("AWS_SECRET_ACCESS_KEY"),
),
)
env = "stg"
response = s3.get_object(
{
bucket: "bucket_name#{env}",
key: "dir/filename.csv",
},
)
input_csv = CSV.new(response.body, headers: true)
progressbar = ProgressBar.create(total: input_csv.count)
input_csv.rewind # progress bar kills csv data
modified_data = []
input_csv.each do |row|
row["new_column_header"] = "value_for_this_line"
modified_data << row
progressbar.increment
end
CSV.open("tmp/modified_data.csv", "wb") do |csv|
csv << modified_data.first.headers
modified_data.each do |row|
csv << row
end
end
s3.put_object(
{
body: File.read("tmp/modified_data.csv"),
bucket: "bucker_name#{env}",
key: "dir/filename_saturated.csv",
},
)
Linting
https://evilmartians.com/chronicles/rubocoping-with-legacy-bring-your-ruby-code-up-to-standard
Leave a comment