https://github.com/crowdhailer/atheneum
Store records how you want them.
https://github.com/crowdhailer/atheneum
Last synced: 10 months ago
JSON representation
Store records how you want them.
- Host: GitHub
- URL: https://github.com/crowdhailer/atheneum
- Owner: CrowdHailer
- License: mit
- Created: 2014-12-12T13:08:35.000Z (about 11 years ago)
- Default Branch: master
- Last Pushed: 2015-01-07T15:55:13.000Z (about 11 years ago)
- Last Synced: 2025-02-07T19:45:00.607Z (11 months ago)
- Language: Ruby
- Homepage: https://rubygems.org/gems/atheneum
- Size: 168 KB
- Stars: 0
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Atheneum
> *noun* **place where records are stored**
#### Turns out this is mostly just a reimplementation of the serialize plugins available with Active Record and Sequel. It might have some value by removeing information about how to serialize of an object. perhaps helping with consistence. Ie as a module serializing a price could be done by saving as an integer while in the process checking a currency method on the class.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'atheneum'
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install atheneum
## Usage
### Basic#
You have a user record, it's always a user, that has a password. There is a `crypted_password` field on your model from the database. Atheneum can use the crypt strategy to take care of storing and retrieving the password. It will also privatise the original attribute accessors so the objects public interface is only the new attribute accessors.
**NB: you must also include bcrypt in your gems for this example**
```rb
class UserRecord < Struct.new(:crypted_password)
include Atheneum.crypt(:password)
end
user_record = UserRecord.new
user_record.password = 'password'
puts user
# => #
user_record.password == 'password'
# => true
user_record.crypted_password
# => NoMethodError: private method `crypted_password' called for #
# Without Atheneum
class UserRecord < Struct.new(:crypted_password)
def password=(password)
self.crypted_password = BCrypt::Password.create(password).to_s
end
def password
BCrypt::Password.new(crypted_password)
end
private :crypted_password, :crypted_password=
end
```
#### Options
Storage methods accept more than one attribute. They also take an optional configuration hash
- **privatise** *(default: true)* Sets whether existing accessors should privatised
- **prefix** Overwrites the strategies default prefix
Strategies with no default prefix will use the strategies name eg `SomeStrategy` => `some_strategy`
#### New Storage Strategy
Say you wanted some strings to be reversed before adding to the database. Perhaps exceptionally mild security.
Atheneum looks up strategy classes namespaced under `Atheneum::Strategy`. These need to implement a pack and unpack method as well as optionally generating the storage location
```rb
module Atheneum
class Strategy
class Reverse < Base
def pack(item)
item.reverse
end
def unpack(item)
item.reverse
end
end
end
end
class LocationRecord < Struct.new(:obscured_address, :obscured_name)
include Atheneum.reverse :address, :name, :prefix => 'obscured', :privatise => false
end
location_record = LocationRecord.new
location_record.name = 'office'
location_record.obscured_name
# => "eciffo"
```
## Why?
By privatising the existing attributes then the record object can remain an *immaculate record*, it appears to have only getters and setters. This is an example of how I have been using them. The example is with sequel, I have yet to try with active record but the priciple should hold.
```rb
require "sequel"
require "atheneum"
require "bcrypt"
# connect to an in-memory database
DB = Sequel.sqlite
# create an users table
DB.create_table :users do
primary_key :id
String :email
String :crypted_password
end
# create a user record
class UserRecord < Sequel::Model(:users)
Atheneum.crypt :password
end
# create a user model
class User < SimpleDelegator
def check_password(candidate_password)
password == candidate_password
end
private
def model
__getobj__
end
end
# In production
user = User.new(UserRecord.new)
user.password = 'password'
user.check_password('password')
# => true
# In test
TestRecord = Struct.new(:email, :password)
user = User.new(TestRecord.new)
user.password = 'password'
user.check_password('password')
# => true
```
#### Immaculate Record
An immaculate record is one that acts purely as a data structure. In practise this works for all classes that can be proxied with a Struct/OpenStruct. Its value is in
- Separating all buisness logic from state
- fast tests
## Contributing
1. Fork it ( https://github.com/[my-github-username]/atheneum/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request