rspec STDOUT

I happened to write some rspec for one ruby program which was accepting some input text in some form, and then it was expected to print the output to the console, or perhaps I did not want to separate the logic of printing. Anyways, that made me expect rspec should check the console output of my program, and after some googling(thanks to many rubyist) I got to work the following


require 'spec_helper'
describe "Transaction" do
it "should handle dummy numerals" do
transaction_input(%{
x1 is I
x5 is V
x10 is X
x50 is L
x100 is C
x500 is D
x1000 is M
how much is x1000 x100 ?
how much is x1 x1 ?
how much is x1 x5 ?
}
).should_output(%{
x1000 x100 is 1100
x1 x1 is 2
x1 x5 is 4
})
end
end

Wow, I liked it.

And the spec_helper made it for me


require "#{File.dirname(__FILE__)}/../lib/transactions.rb"
include Transactions
def capture_stdout(&block)
original_stdout = $stdout
$stdout = fake = StringIO.new
begin
yield
ensure
$stdout = original_stdout
end
fake.string
end
class TransactionInput
def initialize output
@output = output
end
def should_output output
@output.split("\n").should == output.split("\n")[1..-2].collect{|line| line.strip}
end
end
def transaction_input input
TransactionInput.new capture_stdout{ input.split("\n")[1..-2].each{|line| Message.new(line).process} }
end

view raw

spec_helper.rb

hosted with ❤ by GitHub

a quick javascript lightbox

I had to develop some feature which required some javascript lightbox,
I really not needed a fancy one, but a small or medium one
it was for some small confirmation and in addition a couple of inputs on confirmation
so you can imagine a small html form being poped up
I had to add one then, and I guessed tomorrow there might be couple of more coming

I found very nice options when googled
but I thought of implementing one of my own just for fun, and I got this a quick one

admin.lightbox.show(
  html: "my html goes here"
  title: "my title"
).done(->
  alert "Am done"

hi there

And it really took a very less time to build this one as follows


window.admin ||= {}
$.extend window.admin,
lightbox:
show: (options) ->
options = {} unless options
buttonDone = options.buttonDone or "Done"
buttonCancel = options.buttonCancel or "Cancel"
focus = options.focus or "input"
$("body").append "<div id='modal_shadow'></div>" unless $("div#modal_shadow")[0]
$("body").append "<div id='admin-lightbox'></div>" unless $("div#admin-lightbox")[0]
$("div#admin-lightbox").html "<div id='content'>" + options.html + "</div><div id='buttons'></div>"
$("div#admin-lightbox div#buttons").append "<button onclick='admin.lightbox.do_done(); return false;'>" + buttonDone + "</button>"
$("div#admin-lightbox div#buttons").append "<button onclick='admin.lightbox.do_cancel(); return false;'>" + buttonCancel + "</button>"
$("div#admin-lightbox").prepend "<div id='title'>" + options.title + "</div>" if options.title
$("div#modal_shadow").show()
$("div#admin-lightbox").show()
$($("div#admin-lightbox " + focus)[0]).focus()
admin.lightbox
callback_done: null
done: (callback) ->
admin.lightbox.callback_done = callback
admin.lightbox
do_done: ->
try
admin.lightbox.callback_done()
admin.lightbox.hide()
false
callback_cancel: null
cancel: (callback) ->
admin.lightbox.callback_cancel = callback
admin.lightbox
do_cancel: ->
try
admin.lightbox.callback_cancel()
admin.lightbox.hide()
false
hide: ->
$("div#modal_shadow").hide()
$("div#admin-lightbox").hide()
admin.lightbox

The most interesting part here is to be able to define callbacks like done and cancel.


body.active_admin #modal_shadow{
z-index: 999998;
position:fixed;
top: 0px; left: 0px;
height:100%; width: 100%;
background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NsampKAwAFAgHu04pC4AAAAABJRU5ErkJggg==) repeat;
display:none;
padding: 0; margin: 0;
}
body.active_admin #admin-layout{
padding:10px;
margin:10px;
top: 100px;
min-height:100px;min-width:200px;
display:none;
background-color:white;
z-index:999999;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
box-shadow: 0px 5px 19px #777;
-o-box-shadow: 0px 5px 19px #777;
-webkit-box-shadow: 0px 5px 19px #777;
-moz-box-shadow: 0px 5px 19px #777;
position:fixed;
top: 50%;
left: 50%;
margin-left: -200px;
margin-top: -150px;
}
body.active_admin #admin-layout #title{
padding:2px 5px;
background-color: #efefef;
font-weight: bold;
color:#555;
font-size: 1.1em;
margin-bottom: 10px;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
body.active_admin #admin-layout #content{
float:left;
margin-bottom:10px;
}
body.active_admin #admin-layout #buttons{
height:42px;
width:96.5%;
padding:5px;
float:right;
background-color: #efefef;
float:right;
border-bottom: 1px solid #eee;
border-left: 1px solid #eee;
border-right: 1px solid #eee;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
-moz-border-radius-bottomright: 5px;
-moz-border-radius-bottomleft: 5px;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
}
body.active_admin #admin-layout #buttons button{
margin:8px;
padding:8px;
padding-top:6px;
padding-bottom:6px;
float:right;
font-weight: bold;
color:#555;
font-size: 1.0em;
}

And I welcome all suggestions :)

activeadmin cool tweaks

tweak 1: Make some column quick-editable on the index list page

1

Ok… so I want to be quickly able to edit few names, here on the same list page, something like below

2

Thats simply great!

Now it makes me quickly update any name there itself on the list page, <enter> will make it, <escape> will ignore it, and <tab> will move to the next one. awesome.

And to make it work I just need to have one line of code change

All I need to say is `editable_test_column`, and its done.


ActiveAdmin.register Article do
index do
selectable_column
id_column
column :name, :sortable => :name do |resource|
editable_text_column resource, :name
end
column :article_type
column :created_at
column :updated_at
default_actions
end
end

view raw

article.rb

hosted with ❤ by GitHub

And here how it works, you will need to define a couple of things

You need to define editable_text_column, this you could place inside app/admin/lib/


module ActiveAdmin
module Views
class IndexAsTable < ActiveAdmin::Component
def editable_text_column resource, attr
val = resource.send(attr)
val = "&nbsp;" if val.blank?
html = %{
<div id='editable_text_column_#{resource.id}'
class='editable_text_column'
ondblclick='admin.editable_text_column_do(this)' >
#{val}
</div>
<input
data-path='#{resource.class.name.tableize}'
data-attr='#{attr}'
data-resource-id='#{resource.id}'
class='editable_text_column admin-editable'
id='editable_text_column_#{resource.id}'
style='display:none;' />
}
html.html_safe
end

Then you will need to add some javascript …


var admin = {
init: function(){
admin.set_admin_editable_events();
},
set_admin_editable_events: function(){
$(".admin-editable").live("keypress", function(e){
if ( e.keyCode==27 )
$( e.currentTarget ).hide();
if ( e.keyCode==13 ){
var path = $( e.currentTarget ).attr("data-path");
var attr = $( e.currentTarget ).attr("data-attr");
var resource_id = $( e.currentTarget ).attr("data-resource-id");
var val = $( e.currentTarget ).val();
val = $.trim(val)
if (val.length==0)
val = "&nbsp;";
$("div#"+$( e.currentTarget ).attr("id")).html(val);
$( e.currentTarget ).hide();
var payload = {}
resource_class = path.slice(0,1) // e.g. path = meters, resource_class = meter
payload[resource_class] = {};
payload[resource_class][attr] = val;
$.put("/admin/"+path+"/"+resource_id, payload).done(function(result){
console.log(result);
});
}
});
$(".admin-editable").live("blur", function(e){
$( e.currentTarget ).hide();
});
},
editable_text_column_do: function(el){
var input = "input#"+$(el).attr("id")
$(input).width( $(el).width()+4 ).height( $(el).height()+4 );
$(input).css({top: ( $(el).offset().top2 ), left: ( $(el).offset().left2 ), position:'absolute'});
val = $.trim( $(el).html() );
if (val=="&nbsp;")
val = "";
$(input).val( val );
$(input).show();
$(input).focus();
}
}
$( document ).ready(function() {
admin.init();
});

view raw

active_admin.js

hosted with ❤ by GitHub

and some css stuff


input.editable_text_column {
background-color: #FBFF8C;
border: 1px none #FBFF8C;
box-shadow: 0 2px 19px #AAAAAA;
color: black;
display: none;
font-family: serif;
font-size: 1em;
font-style: italic;
height: 30px;
position: absolute;
text-align: center;
vertical-align: middle;
width: 180px;
z-index: 9090;
}
div.editable_text_column{
padding:4px;
background-color: #f9fbc2;
}

Thats it.

Next, I would love to quickly alter article type say having a dropdown there to save my time

tweak 2: quick editable dropdowns on list page

6

Ohh, now this is again great!   … no? It actually updates the article type on value change. nice.

Let see the code behind


ActiveAdmin.register Article do
index do
selectable_column
id_column
column :name, :sortable => :name do |resource|
editable_text_column resource, :name
end
column 'Type', :sortable => :article_type do |resource|
column_select(resource, :article_type, ["News", "Story", "Case Study", "Business"])
end
column :created_at
column :updated_at
default_actions
end
end

view raw

article.rb

hosted with ❤ by GitHub

and to define `column_select`


module ActiveAdmin
module Views
class IndexAsTable < ActiveAdmin::Component
include CustomHelper
def column_select resource, attr, list
val = resource.send(attr)
html = _select list, val, { "attrs" => %{
data-path='#{resource.class.name.tableize}'
data-attr='#{attr}'
data-resource-id='#{resource.id}'
class='admin-selectable'
}
}
html.html_safe
end

CustomHelper is one of my helper modules that really helps me render dropdown the way I need, and provides me some nice options, one may choose to use the default rails select helpers


module CustomHelper
def _select set, selected, options={}
style = "margin:0;padding:0;#{options["style"]}"
selected = options["default"] if selected.blank?
cache = options["cache"] || nil
id = options["id"] || nil
id ||= "ch#{ch_uniq_id}" unless cache.blank?
html = ""
html << "<select "
html << " style='#{style}' "
html << " #{options["attrs"]} "
html << " data-cache='#{cache}' " unless cache.blank?
html << " id='#{id}' " unless id.blank?
html << ">"
if options["blank"]
html << "<option></option>"
end
unless cache.blank?
options_html = Rails.cache.fetch("CustomHelper:#{cache}", expires_in: 1.minute ) { _select_options set, selected, options }
else
options_html = _select_options set, selected, options
end
html << options_html
html << "</select>"
unless cache.blank?
html << %{
<script type="text/javascript">
$( document ).ready(function() {
$("select##{id}").val("#{selected.to_s.strip}");
});
</script>
}
end
html
end
def _select_options set, selected, options
html = ""
selected = selected.to_s.strip
arr_match = options["arr_match"] || 0
set.each do |option|
check = option
value = option
if option.is_a? Array
check = option[arr_match]
value = option[0]
option = option[1]
end
if selected==check.to_s.strip
html << "<option value='#{value}' selected>#{option}</option>"
else
html << "<option value='#{value}'>#{option}</option>"
end
end
html
end
def ch_uniq_id
@ch_uniq_id ||= Time.now.to_i
@ch_uniq_id += 1
end
end

Then you need some javascript


var admin = {
init: function(){
admin.set_admin_selectable_events();
},
set_admin_selectable_events: function(){
$("select.admin-selectable").live("change", function(e){
var path = $( e.currentTarget ).attr("data-path");
var attr = $( e.currentTarget ).attr("data-attr");
var resource_id = $( e.currentTarget ).attr("data-resource-id");
var val = $( e.currentTarget ).val();
val = $.trim(val)
var payload = {}
resource_class = path.slice(0,1)
payload[resource_class] = {};
payload[resource_class][attr] = val;
$.put("/admin/"+path+"/"+resource_id, payload).done(function(result){
console.log(result);
});
});
}
}
$( document ).ready(function() {
admin.init();
});

view raw

active_admin.js

hosted with ❤ by GitHub

done.

I do have worked out several more tweaks like toggle button for boolean column, show/hide columns on the list page, auto-populate/suggest feature for string filters, one can make use ActiveAdmin icons too, then for one of my requirements I have set up the whole custom header and a dozens of custom pages. I would easily say that ActiveAdmin is just simple and awesome, one can really customize it to the extreme, the code structure will allow you to imagine and implement a number of custom scenarios.

DSL approach made it really simple

How much watts we do consume per cycle? Have we joined any of the green innovations like for instance green button. It would be great to know how much watts my house consumed this cycle, will I be able to reduce it, any one out there to help me reduce it. I have so many appliances running at home and I do have a smart meter measuring how much has been consumed. Would you also want to know how does meter measure your watts consumed, and how smart meters provide data for further calculation of your electricity bills.




There are several initiatives taking place in US, PlotWatt, FirstFuel and more, and they help you know your own detailed energy usage, along with other features like calculations, helping you out choosing right pricing plan, giving you several suggestions on how could you reduce your consumption and electricity bills.

Okeh, so this was a quick about Green Button.

Working on one of such initiatives, I came across to define a solution that will enable users to see what electricity bill they would end up paying if they apply some different pricing plan, hence ability to apply different pricing plans against the data consumed for the current or past cycles and being able to compare plans. Rather this would actually help utilities defining their trial plans.

Being rubiest for now more than 5 years, it immediately struck me about having a nice ruby DSL for this one, which could be easier to extend for new rules or sub-requirements. And this was a too much of excitement for me. Writing DSL gives you opportunities to play around ruby mixins, better modeling your classes, modules, beautifully engaging them with each other to work for us and present a nice output.

form

But there was a bad news for me, team decided to do this in python :(  … though still I am to design and develop it.

Not having much exposure to python, having my ruby design plan ready on my mind, I started looking similar python capabilities, parsing, meta-programming, DSL models and more, team as well decided an approach that no need admin to define plans on the fly( like one above), but we could have some fixed plans defined, that actually saved my efforts.

Following is one example of one of those plans we have,


from calc import Calc
from plan import Plan
from datetime import datetime
….
class OurTrialPlan(Plan):
def __init__(self, start_date, end_date, usage, extra=None):
super(OurTrialPlan, self).__init__()
self.calc = Calc(start_date, usage)
self._extra = extra if type(extra)==dict else {}
def calculate(self):
….
add(10, 'customer charges')
# OFF-PEAK
usage = for_month_of(['Jan', 'Feb', 'Oct'])
cost, tier_rate = slab_wise_tariff( usage, no_change_rates)
add( cost, 'no_change', rate=tier_rate)
# KU OFF-PEAK
usage = for_month_of(['Mar', 'Apr', 'May', 'Nov', 'Dec']) and during('10pm','6am')
add( usage*0.0265, 'ke_flat_rate', rate=0.0265)
# KU ON-PEAK
usage = for_month_of(['Mar', 'Apr', 'May', 'Nov', 'Dec']) and during('6am','10pm')
cost, tier_rate = slab_wise_tariff( usage, ke_base_rates)
add( cost, 'ke_base_rates', rate=tier_rate)
cost, tier_rate = slab_tariff( usage, ke_surcharge)
add( cost, 'ke_surcharge', rate=tier_rate)
…..
return tariff()

view raw

TrialPlan.py

hosted with ❤ by GitHub

And we do have several such plans and we could define more, simply focusing on plan rules. The guts have been encapsulated using classes Plan and Calc. Calc helps to collect, compute usage for the specified period, while Plan provides semantics  around.

I did enjoy python scripting a lot, python looks to me as a raw scripting platform where ruby as a very nice, user-friendly scripting platform.

handle_redirect_loop_if_appears


class ApplicationController < ActionController::Base
before_filter :handle_redirect_loop_if_appears
after_filter :set_session_back_url
def handle_redirect_loop_if_appears
return session[:redirect_loop_count] = nil unless request_repeats?
return session[:redirect_loop_count] = 1 unless session[:redirect_loop_count]
max_observed_time_diff_betn_reqs_when_in_loop = 10000
max_loop_count = 3
session[:last_request_time] = Time.now.to_i
session[:redirect_loop_count] += 1
return if session[:redirect_loop_count] < max_loop_count
if last_request_after < max_observed_time_diff_betn_reqs_when_in_loop
session[:last_request_time] = nil
session[:redirect_loop_count] = nil
redirect_to rescue_url and return
end
end
def last_request_after
return unless session[:last_request_time]
time_diff = Time.now.to_isession[:last_request_time].to_i
time_diff = time_diff * (1) if time_diff < 0
end
def rescue_url
home_url
end
def home_url
'/'
end
def request_repeats?
session[:back_url] == request.fullpath
end
def set_session_back_url
return unless request.get?
return if request.xhr?
session[:back_url] = request.fullpath
end
end