layout: post title: Yarn install on Mojave date_string: 27 September 2019 —
If you’re having issues in yarn install
on Mojave, then it’s probably down to the fact
that Mojave doesn’t support different i386 architecture and anything that involves native
building, gems or node modules, seems to fail. The solution is to clean the slate and start
fresh. That’s exactly what I had to do to fix the yarn installation errors:
rm yarn.lock
yarn cache clean
yarn install
These commands worked like a charm!
Hope it helps!
]]>layout: post title: Installing ffi 1.11.1 on Mojave date_string: 27 September 2019 —
If you’ve installed to Mojave and are frustrated by the errors you get on installing ffi (1.11.1), then this blog post is for you.
I had the same issue last week and after trawling through the internet and trying every possible suggestion, one finally worked!
But, before that, a little discussion on the actual error is in order. Below is a small snippet of the actual error on bundle install
:
Configuring libffi for i386
configure: error: in `/Users/andhapp/Projects/github/startup/pimful/vendor/ruby/2.6.0/gems/ffi-1.11.1/ext/ffi_c/libffi-i386':
configure: error: C compiler cannot create executables
See `config.log' for more details
make[1]: *** No targets specified and no makefile found. Stop.
make: *** ["/Users/andhapp/Projects/github/startup/pimful/vendor/ruby/2.6.0/gems/ffi-1.11.1/ext/ffi_c"/libffi-i386/.libs/libffi_convenience.a] Error 2
libffi
is trying to configure for i386 architecture. Mojave doesn’t support that architecture, so the actual linking file is missing. A peek into the
config.log
reveals that fact:
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
ld: warning: ignoring file /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/libSystem.tbd, missing required architecture i386 in file /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/libSystem.tbd
ld: dynamic main executables must link with libSystem.dylib for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
There are several suggestion to actually link the file present in Mojave and make the missing file available that way, but that doesn’t work either.
After several frustrating hours, the following suggestion worked perfectly:
brew reinstall libffi
export LDFLAGS="-L/usr/local/opt/libffi/lib"
export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
Reinstallation of libffi
installs it correctly for Mojave and then bundle install
works like a charm.
Hope it helps!
]]>layout: post title: Don’t blindly follow blog posts date_string: 06 October 2016 —
Technlogy changes fast!
And it’s a blatant fact.
And with changing technology opinions, benchmarks and blog posts become obsolete, fast.
I was reading a blog post recently about adding some performance related gems to improve rails’s performace. It’s a very nice, detailed article with benchmarks.
Instead of just blindly adding the suggested gems to the project, I ran the scripts again and found that:
escape_utils
gem makes things worse on ruby 2.3.1
and rails 5
, so no point in adding it.fast_blank
gem, on the other hand, makes things slightly better, so definitely worth adding. With
slightly better I mean you are able to make more requests/sec.je
and jemalloc
gem didn’t install for ruby 2.3.1
at all.Well, the point of this short blog post was to make you aware that blog posts go out of date and sometimes it’s necessary to re-evaluate the findings and ensure you are adding the gems for the right reasons.
Hope it helps!
]]>layout: post title: Use Sequel for non-rails ruby apps date_string: 14 September 2016 —
I am writing a ruby script to retireve some data via HTTP call and then add it to the database.
Now, I decided to use ActiveRecord as an ORM and wrote a gem for the same.
Nothing complicated. It’s just a Rakefile that provides popular activerecord rake tasks.
But, then I stumbled across blog post on Sequel and I feel Sequel is a better choice for an ORM for a non-rails app.
Why?
Because, Rails is opinionated.
And it’s nuances works nice for a Rails app.
Anything outside of the realms of a standard Rails app and all bets are off.
It is like fitting a square peg in a round hole. It’s possible but you will have to shave off the extra bits.
Sequel on the other hand seems like a better fit for a ruby script.
Will post my experience with Sequel. It has ample documentation and the project was last updated on 16th September 2016. There are no outstanding pull requests or issues on github which implies the project is active and nicely looked after.
]]>layout: post title: Improve Bundler CLI date_string: 29 August 2016 —
Learn another programming language.
Learn from another programming ecosystem.
Learn from another programming language’s tools and bring it back to the language you love.
Fact is, I love Ruby!
However, I’ve been spending a lot of time with Node.js lately. NPM provides a nice way to install any new packages straight from the command line, like:
npm install react --save
I like this convenience.
With an intention to improve Ruby’s ecosystem and tools, I would like to bring this to Ruby.
So, I’ve added a new issue to Bundler. Let’s see what others feel about it.
Update - 31 August 2016
I had a couple of responses for my Bundler issue and it turns out there is indeed a way to add gems via bundler’s CLI.
You can use the inject
command like this:
bundle inject pg 0.18.4
You have to specify the exact version that you want to add though.
Next version of Bundler is going one better and will expose add
command that will add the gem without needing a version number.
layout: post title: Timing attack vulnerability in Rails date_string: 21 February 2016 —
I am not a security expert and this post is my attempt to learn a bit more about web security.
Well, I am signed up to Ruby on Rails security mailing list to make sure vulnerabilities don’t go unnoticed and all my projects are running patched versions. Usually I just read the emails and ensure to upgrade or patch the affected versions and this system has worked very smoothly, however, I have never been happy with this approach and when a timing attack vulnerabilitywas announced on 25th January 2016 (CVE-2015-7576), I decided to research and learn more about it.
A timing attack allows an adversary to learn more about the system under attack by statistically analysing information based on different response times. Here are a few examples:
The size of response for a signed in user and a signed out user will be significantlly different, thus allowing the adversary to determine user’s current state.
A string comparison with no matching characters will be slightly faster than one with 2 matching characters.
There are many more examples along the same lines. One thing worth mentioning is that it takes a lot more analysis and patience for a successful timing attack, but it’s not impossible.
Although, there are several ways to use the timing attack but in the interest of this article the scope is limited to secure string comparison in Ruby. There are two ways to do it:
Activesupport provides a secure_compare
method that can be used like this:
ActiveSupport::SecurityUtils.secure_compare(a, b)
I took this implementation from Time Trial - Racing Towards Practical Remote Timing Attacks paper and looks similar to activesupport’s implementation.
def secure_compare(a, b)
return false if a.empty? || b.empty? || a.bytesize != b.bytesize l = a.unpack "C#{a.bytesize}"
res = 0
b.each_byte { |byte| res |= byte ^ l.shift }
res == 0
end
You may ask why does Ruby not have a secure compare as part of the core API? I have no idea, but, there has been movement on that front lately and you can follow that discussion in ruby’s bug discussion area. It’s currently waiting for Matz approval.
I don’t want to repeat the research that has been conducted by others, so here’s a review of things I researched and if you’re interested you should read these to gain more understanding.
Whilst researching I came across the following tools to test for a timing attack. I’ve not tried them myself but give them a go:
Timing Attacks in Web Applications - Gives a very basic introduction to timing attack vulnerability.
A Lesson In Timing Attacks (or, Don’t use MessageDigest.isEquals) - A very detailed explanation with examples of the actual vulnerability with solutions to fix the issue.
Login timing attacks for mischief and mayhem - This is a presentation into the timing attacks but being a persentation with no audio it’s a bit hard to know the intention of the speaker, nonetheless, full of useful information.
The Clock is Still Ticking: Timing Attacks in the Modern Web - Probably one of the best papers I read with practical examples of attacking popular sites like Facebook and LinkedIn to gain a lot more information regarding site users.
Opportunities and Limits of Remote Timing Attacks - This paper goes into the details of the actual statistical mesaurements required as part of the a successful timing attack. To be honest, I read the beginning and realised the Maths was too complicated for my simple brain.
Web Timing Attacks Made Practical - Again, very thought provoking yet a bit heavy on the statistical analysis which is an integral part of a timing attack.
Time Trial - Racing Towards Practical Remote Timing Attacks - Very detailed and full of great insights. Here’s a companion presentation on youtube.
This research is not comprehensive and I hope its given you enough to carry on this journey by yourself.
Good news! Just seen update on the ruby issue and apparently OpenSSL provides a timing safe binary comparison method called
CRYPTO_memcmp
which is what will be used in ruby internally and exposed from it to be used by other libraries.
With a webpack dev server running, developers can update their code and have the code changes show up straightaway in the browser, thanks to websockets. In order to implement it for a rails application, I did the following:
<% if Rails.env.development? %>
<%= javascript_include_tag 'http://localhost:9999/bundle.js', 'data-turbolinks-track' => true %>
<% else %>
<%= javascript_include_tag 'bundle', 'data-turbolinks-track' => true %>
<% end %>
For development mode, I am downloading the bundle.js
from localhost:9999
. That’s the port where the webpack dev server is running at. For the production mode, the bundle.js
is being read from the `app/assets/javascripts’ directory.
I have the following in my package.json
to to run the webpack dev server on port 9999:
{
"name": "ecommerce-checklist",
"version": "0.0.1",
"description": "Ecommerce checklist",
"scripts": {
"start": "webpack-dev-server --content-base ../app/assets/javascripts --port 9999",
"build": "./node_modules/webpack/bin/webpack.js --progress",
"build:prod": "./node_modules/webpack/bin/webpack.js -p --progress --config webpack.production.config.js"
},
"dependencies": {
"react": "^0.14.2",
"react-dom": "^0.14.2"
},
"devDependencies": {
"babel-core": "^6.0.20",
"babel-eslint": "^4.1.5",
"babel-loader": "^6.0.1",
"babel-preset-es2015": "^6.0.15",
"babel-preset-react": "^6.0.15",
"babel-preset-stage-0": "^6.0.15",
"eslint": "^1.8.0",
"eslint-loader": "^1.1.1",
"eslint-plugin-react": "^3.6.3",
"html-webpack-plugin": "^1.6.2",
"react-hot-loader": "^1.3.0",
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.1"
}
}
Note the bit under scripts -> start
.
This completes the react and webapck setup for a rails application.
One thing to bear in mind, is to create a production ready bundle.js before deploying this application, but that can be part of a capistrano deployment hook.
]]>If you have got two projects using the same functionality, then write a Rubygem to promote code reuse and modularity. Writing a gem is not a new thing. In fact, there are 6,710,940,000 gems and counting, as per the rubygems homepage.
Years ago Jamis Buck said in one of his blogs that if you don’t understand the inner workings of a gem, don’t use it as a dependency. Very fair comment indeed! I’m guilty of using the gems without really knowing their inner workings. To be honest, as a modern day programmer with a constant client expectation to deliver solutions, it’s okay to take your eyes of the ball.
However, I decided to make amendments when it came to integrating a react app into rails. I wanted to learn and fix the issues that comes with integrating and therefore, decided to start it from scratch. If you wish to use, there are a couple of nice integrate react with rails gems out there, namely, react_on_rails and react-rails.
Recently, I have crossed over to the Javascript world and been doing a lot of React, ES6 (with babel) and webpack and I wanted to use the same ideas in a Rails project.
There are a few things to keep in mind:
As part of this article, we are going to set-up a react app in both development and production-mode that will play nicely with a rails app.
As a seasoned rails developer, I expect you guys to know how to do this.
client
at the same level as the app
.package.json
in the client
directory. Package.json is to npm what Gemfile is to Bundler. Copy the following contents into the client/package.json. Most of it is pretty self-explanatory except the scripts section. Npm allows you to create these tasks inside the scripts section runnable from the command line via npm run
command. Under scripts
, start
starts a webpack dev server useful for reloading the app whilst working in development. build
is for building the app locally and uses the default webpack config and finally, build:prod
builds the final distributable js file using webpack’s production config.{
"name": "react-app",
"version": "0.0.1",
"description": "React App",
"scripts": {
"start": "webpack-dev-server --content-base dist/ --port 9999",
"build": "./node_modules/webpack/bin/webpack.js --progress",
"build:prod": "./node_modules/webpack/bin/webpack.js -p --progress --config webpack.production.config.js"
},
"dependencies": {
"react": "^0.14.2",
"react-dom": "^0.14.2"
},
"devDependencies": {
"babel-core": "^6.0.20",
"babel-eslint": "^4.1.5",
"babel-loader": "^6.0.1",
"babel-preset-es2015": "^6.0.15",
"babel-preset-react": "^6.0.15",
"babel-preset-stage-0": "^6.0.15",
"eslint": "^1.8.0",
"eslint-loader": "^1.1.1",
"eslint-plugin-react": "^3.6.3",
"html-webpack-plugin": "^1.6.2",
"react-hot-loader": "^1.3.0",
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.1"
}
}
webpack.base.config.js
in the client
directory with the following contents:*var webpack = require('webpack');
module.exports = {
entry: './src/js/app.js',
output: {
path: '../app/assets/javascripts/',
filename: "bundle.js"
},
module: {
preLoaders: [
{
test: /(\.js$)/,
exclude: /node_modules/,
loader: "eslint-loader"
}
],
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
query: {
presets: [ "react", "es2015", "stage-0" ]
}
}
]
},
eslint: {
configFile: '.eslintrc'
},
plugins: [
new webpack.NoErrorsPlugin()
]
}
webpack.config.js
in the client
directory with the following contents. This is the default config used by webpack.var webpack = require('webpack'),
config = require('./webpack.base.config.js');
config.entry = [
'webpack-dev-server/client?http://0.0.0.0:9999',
config.entry
];
config.output = {
path: config.output.path,
filename: config.output.filename
};
module.exports = config;
webpack.production.config.js
in the client
directory with the following contents. This is mainly used for creating a production ready distributable bundle. It is invoked with a -p
option at the command line to trigger automatic minification.var webpack = require('webpack'),
config = require('./webpack.base.config.js');
config.entry = [
config.entry
];
config.output = {
path: config.output.path,
filename: config.output.filename
};
module.exports = config;
Create a directory called src/js
in the client
directory.
In the src/js
directory, create a file called app.js
. This is the entry file for webpack. Entry file is the file webpack uses to workout all the other dependencies that it needs to bundle up in the final distributable file.
The app.js
file should have the following contents. This is the entry point for the app. Here it’s rendering the react app in a dom node with the id react-app
. Make sure a dom node with the same id exists in the layout file of your rails app, otherwise, react will have no place to mount the app.
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App.react'
ReactDOM.render(
<App />,
document.getElementById('react-app')
);
App
is written in ES6 classes and takes advantage of the modular dependency provided by ES6 out of the box.import React, { Component, PropTypes } from 'react'
class App extends Component {
render() {
return (
<div>
<h1>React App</h1>
</div>
);
}
}
export default App
npm run build
. This will create a bundle.js (development version) and to app/assets/javascripts
directory.config/initializers/assets.rb
as a precompiled file:Rails.application.config.assets.precompile += %w( bundle.js )
Added it at the bottom of the layout file with a script tag to ensure the DOM node that react app depends upon is there before react’s mounting kicks in.
Opened the rails root page in a browser to check the react app is being mounted correctly and React App
(the contents of the App.react.js component) is being rendered on the page.
application.js
in your rails layout file fixes this issue.Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.
And, that’s it!
Update: 06 December 2015
The following error
Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.
is my fault. In my app/assets/javascripts/application.js
, I had the line to include the bundle.js file and since this file is brought into the layout in the head section - when the DOM node that react app needs is not ready - it throws an error. We use bundle.js
as a precompiled asset, so we don’t need to bring it in as part of appication.js
. There’s an easy fix in Sprockets for it. If you would like to ignore a file in your directory you use the stub
call. So, my application.js
file now looks like:
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
//= stub bundle
What has a gem got to do with Rails? You write ruby gems and rails is just another gem, no?
Correct!
It has nothing to do with Rails but my Ruby adventure began with Rails and I for one give the credit where it’s due, without a shadow of doubt.
Anyways, around 4 years ago, I created a gem called is_bot. It offers some spam protection for web forms. I can’t even remember the project I used it on back then. However, recently we’ve been marketing Suggestion.io and encountered a lot of spam sign ups and decided to fix the issue.
I hate asking prospective clients to fill in yet another field. You want to make it easier not difficult to sign up. is_bot is different. It just adds a invisible text field making it hidden from the actual users. Time to get one back on the damn bots!
I looked at few existing gems but none worked nicely. It was time to reboot is_bot. Back then it was written for Rails 3 so had to upgrade it for Rails 4 APIs which was a bit of a pain since it’s hard to find what changed from Rails 3 to Rails 4, easily. Reading through Rails source code and looking at some of the other gems got us through.
I also took this opportunity to change a few more things…I say a few, but so much has changed, hasn’t it?
.rvmrc
to .ruby-gemset
and .ruby-version
.It was a bit of a work, but in the end all the efforts paid off.
]]>However, can we remove the methods from a Ruby class?
I encountered two ways of removing methods from a class:
There are subtle differences between the two. The former removes the method from the current class, where as the latter, stops responding to the methods in the current class.
Let’s look at an example for the same. Imagine we have a parent class, Appliance (a.k.a Kitchen Appliance), and child class, Can opener. Here are the definitions for the two classes:
class Appliance
def name
puts "I'm a kitchen appliance"
end
end
class CanOpener < Appliance
def name
puts "I'm a can opener"
end
end
Now, let’s try remove_method
and see what happens.
can_opener = CanOpener.new
can_opener.name
class CanOpener
remove_method :name
end
can_opener.name
puts "Can Opener has a name? #{can_opener.respond_to?(:name)}"
This will produce the following output:
I'm a can opener
I'm a kitchen appliance
Can Opener has a name? true
As soon as you remove a method from a class it treats the method as
undefined and goes up the ancestor chain to look for an implementation,
which it finds in the parent class. Since, there’s an implementation
respond_to
returns true.
However, undef_method
works slightly differently and let’s see how:
class Appliance
def name
puts "I'm a kitchen appliance"
end
end
class CanOpener < Appliance
def name
puts "I'm a can opener"
end
end
can_opener = CanOpener.new
can_opener.name
class CanOpener
undef_method :name
end
puts "Can Opener has a name? #{can_opener.respond_to?(:name)}"
can_opener.name
This will produce the following output:
I'm a can opener
Can Opener has a name? true
/tmp/execpad-f7201e261f52/source-f7201e261f52:21:in `<main>': undefined method `name' for #<CanOpener:0x41017dcc> (NoMethodError)
Unlike remove_method
, undef_method
stops responding to the method
and doesn’t travel up the ancestor chain. It totally disregards the
method implementation in the parent class.
Quite interesting, however, I’ve never seen it used in any of the production code before, so, hopefully, I will find a good use case for it soon.
]]>Recently, I was reading some open source code recently and spotted $DEBUG environment variable in quite a few places. At the time, I thought it must be something the author used to simplify debugging. But, no, it’s defined and used by ruby core. Ruby provides a debug flag (-d or –debug) which when used would set the $DEBUG to true.
Try running the following script in irb, pry or whatever else you use:
ruby -d -e 'if $DEBUG; puts "Debugging"; end'
and you should see something like this as output:
RUBY_GC_HEAP_FREE_SLOTS=200000 (default value: 4096)
RUBY_GC_MALLOC_LIMIT=90000000 (default value: 16777216)
Exception `LoadError' at /Users/andhapp/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/rubygems.rb:1222 - cannot load such file -- rubygems/defaults/operating_system
Exception `LoadError' at /Users/andhapp/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/rubygems.rb:1231 - cannot load such file -- rubygems/defaults/ruby
Debugging
Don’t worry about the two exceptions as in debug mode exceptions are displayed even when they are rescued.
]]>You would probably see the following error:
Selenium::WebDriver::Error::UnknownError: unknown error: cannot find Chrome binary
There are two ways to fix this issue:
### Solution 1 - Download Chrome
Whilst, searching for the solution, I ended up on ChromeDriver’s wiki. It clearly states that Chrome driver expects the Chrome binary to be in:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome
That’s exactly where Chrome is installed on a Mac, so, to fix this issue just download Chrome.
Downloading Chrome just for the sake of passing specs doesn’t make sense. Googling revealed that there’s something called ‘ChromeOptions’, but, how the hell do I pass that option from Capybara, so that it get’s passed correctly to Selenium Chrome driver. After, trawling through the capybara and selenium-webdriver source, I found a way to pass the location of Chrome Canary as the binary. Here’s how:
Capybara.register_driver :chrome do |app| Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: { "chromeOptions" => { "binary" => '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary' } }) end
The ‘binary’ option specifies the location of Chrome Canary’s binary on your Mac.
That was a couple of hours well spent. Hope it helps!
]]>I just found it very fascinating and challenging at the same time.
]]>Whilst merging pull request for TextRazor, I decided to upgrade the gem to RSpec3. I was meant to do that for sometime anyways, and the pull request opened up the perfect opportunity for it. I stumbled upon a very interesting new feature in RSpec3, called verifying doubles. This functionality makes rspec-fire totally obsolete. It verifies that any methods being stubbed would be present on the instance of the class being stubbed and also the number of argument the method accepts. This is pretty cool. I always used rspec-fire to make sure that my stubbed method existed on the class. In the light of these updates, I removed rspec-fire as a dependency from TextRazor. Makes it even more lightweight.
Thanks again to RSpec team!
]]>irb(main):001:0> puts "First", "day" First day => nil
irb(main):004:0> puts ["Second", "Day"] Second Day => nil
Hope you can use this to replace multiple calls to puts in your code.
]]>No one has time!
The rise of billion dollar startups that get acquired in 6 months (or longer, perhaps) from launch gives a false impression that programming is easy, and hence shouldn’t take very long to learn. After all, you have a billion dollar idea you would like to start working on.
Let’s conduct a small study. Why don’t you spend an hour on StackOverflow? Why? To observe how users, without doing any research, ask the same questions over and over and over again. They just want to learn how this works, not why this works and not something else. I’m possibly guilty of the same mistakes, and I have been trying to amend them ever since.
As a result of these observations, and experience in teaching, I’ve come up up with a list of few qualities that can make you a better programmer:
Learner - Learning never stops for a programmer and that’s the fun of it. You will have to spend extra hours every week to brush up your skills, gain new skills, and get better at your trade.
Committed - It’s not easy to become a programmer. It will require a lot of commitment, practice, and more programming, of course.
Investigative - You may end up spending days trying to fix a Javascript memory leak, or why your Rails app is running slow and leaking memory. It will require a lot of investigation, research and thinking about every aspect of the application, and it’s behaviour. You will have to read API documents, source code, and so on.
All in all, it’s not going to be easy.
Now, do you still want to be a programmer?
]]>Abbrev calculates the set of unique abbreviations for a given set of strings. The following code demonstrates it properly:
require 'abbrev'
require 'pp'
pp Abbrev.abbrev(['ruby', 'rules'])
This code produces the following output where all the keys are abbreviated and unique, and point to their respective words.
{"ruby"=>"ruby",
"rub"=>"ruby",
"rules"=>"rules",
"rule"=>"rules",
"rul"=>"rules"}
This also provides an extension for an Array, so you can call ‘abbrev’ method straight on an array. The code above will then become:
require 'abbrev'
require 'pp'
pp ['ruby', 'rules'].abbrev
I found a couple of use cases of the Abbrev module on Google:
For creating unique labels for a bar graph.
For creating an auto-completer on console, intriguing, right?
Hope this will make you aware of such a nifty module and please share your use-cases with the rest of us.
]]>Years ago, I was discussing some issue regarding GemCutter (now that makes it ancient in programming age), and we were talking about global variables in Ruby, for example, $; and $/. At the time, we couldn’t really find a place to look them up, even Google isn’t very effective given the nature of the query.
Anyways, while looking through Ruby’s standard library, I found the file English.rb. This library has English names for all the cryptic global variables. For example: $ERROR_INFO represents $!.
If you ever have to look up the English names, which I suggest you do as it makes code easier to read, just refer to that file.
]]>class Car
def self.start
begin
1/0
rescue => ex
puts "Exception: #{ex}"
raise StandardError.new "Can't start the car"
end
end
end
begin
Car.start
rescue => ex
puts "Cause: #{ex.cause}"
puts "Exception: #{ex}"
end
This will produce the following output:
Exception: divided by 0
Cause: divided by 0
Exception: Can't start the car
You can play around with the code yourself. It’s not as sophisticated as the gems out there, but it’s getting there.
]]>Anyways, TracePoint is not the scope of this post. This post is all about AOP, or Aspect Oriented Programming.
Wikipedia defines it as “aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. AOP forms a basis for aspect-oriented software development.”
There are couple of things worth noting, Modularity and Cross-cutting concerns.
In English, Modularity means based on modules, easily assembled, or repaired and the reason it’s easily repaired is because modules are self-contained and talk to each other via a defined interface. Interface could be hardware pins, RAM slots, or intangible ones, defined in your Ruby or Java class.
In Ruby world, modules and modularity is the go-to thing to achieve separation of concern. You got a piece of code that is used in two different places and has no state of its own, just create a module to be included/extended or prepended.
Cross-cutting concern can be defined as any piece of code that’s more widely used across the application, for example, logging, security, or authentication, perhaps. Something, like a before_filter in Rails controllers that’s applied to a set of actions.
There are libraries that one could use to achieve same and even more than before_filter functionality outside of Rails. The one that I briefly looked at is called Aspector. It provides a lot of examples as well just in case you are stuck.
Ruby modules are similar but not exactly same as the AOP concept. One important difference is that you can apply an aspect (aspect is the piece of code with common functionality, like a module) to a class from outside, without opening the class. Here’s some aspector code snippet to elaborate the point:
TestAspect.apply A
Here A is the class, and TestAspect is the aspect. As you can see, you can just apply it from outside. Sorry, not very clear, but I didn’t want to tie the concept to a particular library implementation.
One good use case of using AOP concepts would be with something like debugging, for example, a user performed an action and you want to check the log for parameters that are getting passed in to methods, or what methods are getting called when certain action is performed. But, that’s what TracePoint does, right? Well, it definitely allows one to hook into the events and print debugging information. With AOP, one can create more focussed debugging. Imagine, a request going through Rails stack will hit a lot of methods and you don’t want to enable tracing and then having to go through a long console output.
These are just some of the initial thoughts I had on reading AOP and TracePoint. Hope this post will encourage you to investigate and learn more about these topics.
]]>