Showing posts with label plugin. Show all posts
Showing posts with label plugin. Show all posts

Thursday, December 13, 2007

ThreadsafeBenchmark

When testing products such as services which need to be stress-tested prior to release, it's necessary to use multi-threading to get as close to real world usage as possible. This gem, though not intended to be a replacement for full-fledged testing suites such as LoadRunner, can provide instantaneous results to facilitate TDD programming. To reduce the duplication of code, the gem utilizes Ruby's built-in Benchmark module for the base functionality while preventing the output from clobbering through the use of thread-specific IO buffers.

require 'threadsafe_benchmark'
include ThreadsafeBenchmark

threads = []
max_num = 5000

5.to_i.times { |i|
threads << Thread.new(max_num) { |n|
threadsafe_bm(6) { |x|
x.report("for:") { for i in 1..n; a = "1"; end }
x.report("times:") { n.times do ; a = "1"; end }
x.report("upto:") { 1.upto(n) do ; a = "1"; end }
}
}
}

threads.each { |t| t.join }

Using the standard Benchmark, the results would be printed haphazardly making it difficult to read and interpret. But ThreadsafeBenchmark cleans everything up giving us nicely laid out columns.

usersystemtotalreal
for0.000000.000000.000000( 0.002889)
times0.000000.000000.000000( 0.002477)
upto0.000000.000000.000000( 0.002479)
for0.000000.000000.000000( 0.002401)
times0.010000.000000.010000( 0.002586)
upto0.000000.000000.000000( 0.002413)
for0.000000.000000.000000( 0.002205)
times0.010000.000000.010000( 0.002245)
upto0.000000.000000.000000( 0.002272)
for0.000000.000000.000000( 0.001822)
times0.010000.000000.010000( 0.001958)
upto0.000000.000000.000000( 0.001943)
for0.010000.000000.010000( 0.010090)
times0.010000.000000.010000( 0.009225)
upto0.010000.000000.010000( 0.007986)

The gem and source files are available at Rubyforge.

Friday, May 11, 2007

Plugin I Cannot Live Without

The Enhanced Rails Migrations plugin was written to end the constant battle we had with clashing names in db migrations within our large development team. We tried everything: special commit policies, rake tasks, even claiming the next migration number in subversion. Nothing worked and CI server was sending 'broken build due to conflicting migration number' messages almost daily. Since the plugin was introduced to all our rails applications around six months ago, I have not heard of a single case of conflicting migrations. Seemingly, the goal was well accomplished.

What I found over time, is that the plugin is not only useful for large projects. Any rails development effort with more than one programmer involved benefits from using it. If you ever had to renumber your new migration after doing svn up you know what I am talking about. It makes sense to install this plugin as the very first one in your project since an amount of migrations at the beginning tends to grow much faster then later in the game.

The plugin works for rails versions 1.1.6 up to the latest edge. When you start your next project with multiple developers, use it and you should be able to forget that you ever had problems with clashing migrations.

Thursday, April 26, 2007

[PLUGIN RELEASE] ActsAsSecure

Introduction

ActsAsSecure adds an ability to store ActiveRecord model's fields encrypted in a DB. When a model is marked with acts_as_secure, the :binary type fields are recognized as needed to be stored encrypted. The plugin does before_save/after_save/after_find encryption/decryption thus making it transparent for a code using secured models.

The plugin supports a master key approach as well as individual records encryption keys. It does not contain any crypto provider but allows to plug in any external one as long as it supports encrypt/decrypt methods.

The fields are converted to a YAML form before encryption. After description they are restored via YAML.load. Since fields are stored encrypted, the find usage is very limited.

Usage

Master Key Provider Usage

class SecureModel < ActiveRecord::Base
acts_as_secure :crypto_provider => MasterKeyProviderClassOrInstance
end

SecureModel.create()
SecureModel.find(:first)

Individual Keys Provider Usage
class SecureModel < ActiveRecord::Base
acts_as_secure
end

SecureModel.with_crypto_provider(SomeProvider.new(some_param)) { SecureModel.find(:first) }
SecureModel.with_crypto_provider(SomeProvider.new(some_param)) { SecureModel.create() }

Other Options

acts_as_secure :storage_type => :text -- changes the secure storage type from :binary to the supplied one
acts_as_secure :except => [:field1, :field2] -- disables the secure behavior for the :binary type fields in a supplied list


Example

Let's define three models: Fruit (not secure), SecretFruit (uses the master key approach), and UberSecretFruit (uses the individual key approach).

Rot13CryptoProvider represents a master key provider. SaltedRot13CryptoProvider depends on a salt individual for each record.

Models
class Fruit < ActiveRecord::Base
has_one :secret_fruit
has_one :uber_secret_fruit
end

class CreateFruits < ActiveRecord::Migration
def self.up
create_table :fruits do |t|
t.column :name, :string
end
end
end

class Rot13CryptoProvider
class << self
def encrypt(arg)
arg.tr("A-Za-z", "N-ZA-Mn-za-m")
end
alias_method :decrypt, :encrypt
end
end

class SecretFruit < ActiveRecord::Base
acts_as_secure :crypto_provider => Rot13CryptoProvider
belongs_to :fruit
end

class CreateSecretFruits < ActiveRecord::Migration
def self.up
create_table :secret_fruits do |t|
t.column :name, :binary
t.column :fruit_id, :integer
end
end
end

class SaltedRot13CryptoProvider
def initialize(salt)
@salt = salt
end
def encrypt(arg)
@salt + arg.tr("A-Za-z", "N-ZA-Mn-za-m")
end
def decrypt(arg)
arg[@salt.size .. -1].tr("A-Za-z", "N-ZA-Mn-za-m")
end
end

class UberSecretFruit < ActiveRecord::Base
acts_as_secure
belongs_to :fruit
end

class CreateUberSecretFruits < ActiveRecord::Migration
def self.up
create_table :uber_secret_fruits do |t|
t.column :name, :binary
t.column :fruit_id, :integer
end
end
end



Usage

>> f = Fruit.create(:name => 'passion fruit')
>> SecretFruit.create(:name => 'maracuya', :fruit => f)
>> puts f.secret_fruit.name
maracuya
>> secret = readline.chomp
uber_secret
>> crypto_provider = SaltedRot13CryptoProvider.new(secret)
>> UberSecretFruit.with_crypto_provider(crypto_provider) { UberSecretFruit.create(:name => 'Passiflora edulis', :fruit => f) }
>> UberSecretFruit.with_crypto_provider(crypto_provider) { puts f.uber_secret_fruit.name }
Passiflora edulis


DB
> select * from secret_fruits;
+----+---------------+----------+
| id | name | fruit_id |
+----+---------------+----------+
| 1 | --- znenphln | 1 |
+----+---------------+----------+

> select * from uber_secret_fruits;
+----+-----------------------------------+----------+
| id | name | fruit_id |
+----+-----------------------------------+----------+
| 1 | uber_secret--- Cnffvsyben rqhyvf | 1 |
+----+-----------------------------------+----------+


Installation

As plugin:
script/plugin install svn://rubyforge.org/var/svn/acts-as-secure/trunk/vendor/plugins/acts_as_secure


License

ActsAsSecure released under the MIT license.


Support

The plugin RubyForge page is http://rubyforge.org/projects/acts-as-secure