Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit 4b1b5875933779026bd66fb666b1d8eda8e0aa7f 0 parents
@kenn authored
17 .gitignore
@@ -0,0 +1,17 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
1  .rspec
@@ -0,0 +1 @@
+--color
3  Gemfile
@@ -0,0 +1,3 @@
+source 'https://rubygems.org'
+
+gemspec
22 LICENSE.txt
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Kenn Ejima
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 README.md
@@ -0,0 +1,29 @@
+# StoreField
+
+TODO: Write a gem description
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+ gem 'store_field'
+
+And then execute:
+
+ $ bundle
+
+Or install it yourself as:
+
+ $ gem install store_field
+
+## Usage
+
+TODO: Write usage instructions here
+
+## Contributing
+
+1. Fork it
+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 new Pull Request
6 Rakefile
@@ -0,0 +1,6 @@
+require 'bundler/gem_tasks'
+
+# RSpec
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec)
+task :default => :spec
42 lib/store_field.rb
@@ -0,0 +1,42 @@
+require 'store_field/version'
+require 'store_field/railtie'
+require 'active_record'
+
+module StoreField
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def store_field(key, options = {})
+ raise ArgumentError.new(':in is invalid') if options[:in] and serialized_attributes[options[:in].to_s].nil?
+ raise ArgumentError.new(':type is invalid') if options[:type] and ![ Hash, Set ].include?(options[:type])
+
+ store_attribute = options[:in] || serialized_attributes.keys.first
+ raise ArgumentError.new('store method must be defined before store_field') if store_attribute.nil?
+
+ # Accessor
+ define_method(key) do
+ value = send("#{store_attribute}")[key]
+ if value.nil?
+ value = store_field_init(options[:type])
+ send("#{store_attribute}")[key] = value
+ end
+ value
+ end
+
+ # Utility methods for Set
+ if options[:type] == Set
+ define_method("set_#{key}") {|value| send(key).add(value); self }
+ define_method("unset_#{key}") {|value| send(key).delete(value); self }
+ define_method("set_#{key}?") {|value| send(key).include?(value) }
+ define_method("unset_#{key}?") {|value| !send(key).include?(value) }
+ end
+ end
+ end
+
+ def store_field_init(klass)
+ return {} unless klass
+ klass.new
+ end
+end
+
+ActiveRecord::Base.send(:include, StoreField)
11 lib/store_field/railtie.rb
@@ -0,0 +1,11 @@
+module StoreField
+ if defined? Rails::Railtie
+ class Railtie < Rails::Railtie
+ initializer 'store_field.insert_into_active_record' do |app|
+ ActiveSupport.on_load :active_record do
+ include StoreField
+ end
+ end
+ end
+ end
+end
3  lib/store_field/version.rb
@@ -0,0 +1,3 @@
+module StoreField
+ VERSION = '0.0.1'
+end
11 spec/spec_helper.rb
@@ -0,0 +1,11 @@
+require 'rubygems'
+require 'bundler/setup'
+
+require 'store_field'
+
+RSpec.configure do |config|
+ ActiveRecord::Base.send(:include, StoreField)
+
+ # Establish in-memory database connection
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
+end
56 spec/store_field_spec.rb
@@ -0,0 +1,56 @@
+require 'spec_helper'
+
+ActiveRecord::Base.connection.create_table :users, force: true do |t|
+ t.text :storage
+end
+
+class User < ActiveRecord::Base
+ store :storage
+ store_field :preference
+ store_field :count_caches
+ store_field :notified, type: Set
+ store_field :displayed, type: Set
+ store_field :funnel, type: Set
+end
+
+describe StoreField do
+ before do
+ @user = User.new
+ end
+
+ it 'raises when store is not defined beforehand' do
+ expect { Class.new(ActiveRecord::Base) { store :storage; store_field :notified } }.to_not raise_error(ArgumentError)
+ expect { Class.new(ActiveRecord::Base) { store_field :notified } }.to raise_error(ArgumentError)
+ end
+
+ it 'raises when invalid option is given' do
+ expect { Class.new(ActiveRecord::Base) { store :storage; store_field :notified, type: File } }.to raise_error(ArgumentError)
+ expect { Class.new(ActiveRecord::Base) { store :storage; store_field :notified, in: :bogus } }.to raise_error(ArgumentError)
+ end
+
+ it 'initializes with the specified type' do
+ @user.preference.should == {}
+ @user.notified.should == Set.new
+ end
+
+ it 'sets and unsets keywords' do
+ @user.set_notified(:welcome)
+ @user.set_notified(:first_deposit)
+
+ # Consume balance, notify once and only once
+ @user.set_notified(:balance_low)
+ @user.set_notified(:balance_negative)
+
+ # Another deposit, restore balance
+ @user.unset_notified(:balance_low)
+ @user.unset_notified(:balance_negative)
+
+ @user.notified.should == Set.new([:welcome, :first_deposit])
+ end
+
+ it 'saves in-line' do
+ @user.set_notified(:welcome).save.should == true
+ @user.reload
+ @user.set_notified?(:welcome).should == true
+ end
+end
24 store_field.gemspec
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'store_field/version'
+
+Gem::Specification.new do |gem|
+ gem.name = 'store_field'
+ gem.version = StoreField::VERSION
+ gem.authors = ['Kenn Ejima']
+ gem.email = ['kenn.ejima@gmail.com']
+ gem.description = %q{Typed fields for ActiveRecord::Store}
+ gem.summary = %q{Typed fields for ActiveRecord::Store}
+ gem.homepage = 'https://github.com/kenn/store_field'
+
+ gem.files = `git ls-files`.split($/)
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
+ gem.require_paths = ['lib']
+
+ gem.add_runtime_dependency 'activerecord', '>= 3.2.0'
+
+ gem.add_development_dependency 'rspec'
+ gem.add_development_dependency 'sqlite3'
+end
Please sign in to comment.
Something went wrong with that request. Please try again.