redinger-hashdown 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
@@ -0,0 +1,2 @@
1
+ == 0.1.1
2
+ * gemified by Christopher Redinger
@@ -0,0 +1,58 @@
1
+ = hashdown
2
+
3
+ http://github.com/rubysolo/hashdown
4
+
5
+ == DESCRIPTION:
6
+
7
+ hashdown is a super lightweight rails plugin that adds hash-style lookups and option lists (for generating dropdowns) to ActiveRecord models
8
+
9
+ == EXAMPLE:
10
+
11
+ Given the following class definition:
12
+
13
+ class State < ActiveRecord::Base
14
+ finder :abbreviation
15
+ selectable
16
+ end
17
+
18
+ You can look up states via their abbreviations like so:
19
+
20
+ @colorado = State[:CO]
21
+
22
+ These types of reference data models are often something you need to populate a select list on your form, so hashdown includes a handy method to generate your option list:
23
+
24
+ <%= form.select :state_id, State.select_options %>
25
+
26
+ This is roughly equivalent to the following implementation:
27
+
28
+ class State < ActiveRecord::Base
29
+ validates_uniqueness_of :abbreviation
30
+
31
+ def self.[](state_code)
32
+ find_by_abbreviation(state_code)
33
+ end
34
+
35
+ def self.select_options
36
+ find(:all).map{|s| [s.name, s.id] }
37
+ end
38
+ end
39
+
40
+ ...except it adds ActiveSupport caching for speedy lookups.
41
+
42
+ == COMING SOON:
43
+
44
+ * configuration for key / value generation
45
+ * app level
46
+
47
+ == LICENSE:
48
+
49
+ (The MIT License)
50
+
51
+ Copyright © 2008-2009 Solomon White
52
+
53
+ 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:
54
+
55
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
56
+
57
+ 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.
58
+
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "hashdown"
8
+ gem.summary = %Q{hash-style lookups and option lists}
9
+ gem.description = %Q{hashdown is a super lightweight rails plugin that adds hash-style lookups and option lists (for generating dropdowns) to ActiveRecord models}
10
+ gem.email = "redinger@gmail.com"
11
+ gem.homepage = "http://github.com/redinger/hashdown"
12
+ gem.authors = ["Solomon White", "Christopher Redinger"]
13
+ gem.add_development_dependency "rspec"
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
17
+ end
18
+
19
+ require 'spec/rake/spectask'
20
+ Spec::Rake::SpecTask.new(:spec) do |spec|
21
+ spec.libs << 'lib' << 'spec'
22
+ spec.spec_files = FileList['spec/**/*_spec.rb']
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.pattern = 'spec/**/*_spec.rb'
28
+ spec.rcov = true
29
+ end
30
+
31
+ task :spec => :check_dependencies
32
+
33
+ task :default => :spec
34
+
35
+ require 'rake/rdoctask'
36
+ Rake::RDocTask.new do |rdoc|
37
+ if File.exist?('VERSION')
38
+ version = File.read('VERSION')
39
+ else
40
+ version = ""
41
+ end
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "hashdown #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 1
3
+ :patch: 1
4
+ :major: 0
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{hashdown}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Solomon White", "Christopher Redinger"]
12
+ s.date = %q{2009-09-24}
13
+ s.description = %q{hashdown is a super lightweight rails plugin that adds hash-style lookups and option lists (for generating dropdowns) to ActiveRecord models}
14
+ s.email = %q{redinger@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "CHANGELOG",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION.yml",
24
+ "hashdown.gemspec",
25
+ "init.rb",
26
+ "lib/finder.rb",
27
+ "lib/hashdown.rb",
28
+ "lib/selectable.rb",
29
+ "rails/init.rb",
30
+ "spec/finder_spec.rb",
31
+ "spec/fixtures/currencies.yml",
32
+ "spec/fixtures/states.yml",
33
+ "spec/selectable_spec.rb",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/redinger/hashdown}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.5}
40
+ s.summary = %q{hash-style lookups and option lists}
41
+ s.test_files = [
42
+ "spec/finder_spec.rb",
43
+ "spec/selectable_spec.rb",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ s.add_development_dependency(%q<rspec>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<rspec>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<rspec>, [">= 0"])
58
+ end
59
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'hashdown'
@@ -0,0 +1,28 @@
1
+ module Rubysolo # :nodoc:
2
+ module Hashdown
3
+
4
+ module Finder
5
+ def self.included(base)
6
+ base.instance_eval do
7
+ validates_uniqueness_of finder_attribute
8
+
9
+ cattr_accessor :cache_store
10
+ self.cache_store ||= ActiveSupport::Cache::MemoryStore.new
11
+
12
+ def self.[](token)
13
+ cache_store.fetch("[]:#{token}", :force => Rubysolo::Hashdown.force_cache_miss?) {
14
+ returning find(:first, :conditions => { finder_attribute => token.to_s}) do |record|
15
+ raise "Could not find #{self.class_name} with #{finder_attribute} '#{token}'" unless record
16
+ end
17
+ }
18
+ end
19
+ end
20
+ end
21
+
22
+ def is?(token)
23
+ self[self.class.finder_attribute] == token.to_s
24
+ end
25
+ end # Finder
26
+
27
+ end
28
+ end
@@ -0,0 +1,44 @@
1
+ require 'activesupport' unless defined? ActiveSupport
2
+ require 'activerecord' unless defined? ActiveRecord
3
+ require 'finder'
4
+ require 'selectable'
5
+
6
+ module Rubysolo # :nodoc:
7
+ module Hashdown
8
+ def self.included(base) # :nodoc:
9
+ base.extend ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ def finder(attr_name)
14
+ class << self
15
+ attr_accessor :finder_attribute
16
+ end
17
+ self.finder_attribute = attr_name
18
+
19
+ self.send :include, Finder
20
+ end
21
+
22
+ def selectable(options={})
23
+ class << self
24
+ attr_accessor :selectable_options
25
+ end
26
+ self.selectable_options = options
27
+
28
+ self.send :include, Selectable
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def self.force_cache_miss?
35
+ defined?(Rails) && Rails.env.test?
36
+ end
37
+
38
+
39
+ end # Hashdown
40
+ end # Rubysolo
41
+
42
+ ActiveRecord::Base.class_eval do
43
+ include Rubysolo::Hashdown
44
+ end
@@ -0,0 +1,44 @@
1
+ module Rubysolo # :nodoc:
2
+ module Hashdown
3
+
4
+ module Selectable
5
+ def self.included(base)
6
+ base.instance_eval do
7
+ cattr_accessor :cache_store
8
+ self.cache_store ||= ActiveSupport::Cache::MemoryStore.new
9
+
10
+ def self.select_options(*args)
11
+ cache_store.fetch("select_options:#{args.hash}", :force => Rubysolo::Hashdown.force_cache_miss?) {
12
+ options = args.extract_options!
13
+ options[:value] ||= args.shift || selectable_options[:value]
14
+
15
+ [:display_name, :name].each {|sym| options[:value] ||= sym if instance_methods.include?(sym.to_s) || has_column?(sym) } unless options[:value]
16
+ raise "#{self} does not respond to :display_name or :name. Please specify a value method." unless options[:value]
17
+
18
+ options[:key] ||= args.shift || selectable_options[:key]
19
+ options[:key] ||= :id
20
+
21
+ find_options = scope(:find) || {}
22
+ find_options[:order] = options[:order] if options.has_key?(:order)
23
+ find_options[:order] ||= options[:value] if has_column?(options[:value])
24
+
25
+ find(:all, find_options).map{|record| record.to_pair(options[:key], options[:value]) }
26
+ }.dup
27
+ end
28
+
29
+ def self.has_column?(column_name)
30
+ columns.map{|c| c.name }.include?(column_name.to_s)
31
+ end
32
+ end
33
+ end
34
+
35
+ def to_pair(key_generator, val_generator)
36
+ key = key_generator.respond_to?(:call) ? key_generator.call(self) : self.send(key_generator)
37
+ val = val_generator.respond_to?(:call) ? val_generator.call(self) : self.send(val_generator)
38
+
39
+ [val, key]
40
+ end
41
+ end # Selectable
42
+
43
+ end
44
+ end
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/../init"
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe "an ActiveRecord model with finder defined" do
4
+
5
+ before(:each) do
6
+ Rails.test_environment = false
7
+ State.cache_store.clear
8
+ load_fixtures
9
+ end
10
+
11
+ after(:each) do
12
+ cleanup_db
13
+ end
14
+
15
+
16
+ it "should respond to []" do
17
+ State.should.respond_to? :[]
18
+ end
19
+
20
+ it "should enforce uniqueness of lookup token" do
21
+ State[:CO].name.should == "Colorado"
22
+ @state = State.new(:abbreviation => "CO")
23
+ @state.should_not be_valid
24
+ end
25
+
26
+ it "should support hash-like lookup" do
27
+ @colorado = State.find_by_name 'California'
28
+ State[:CA].should == @colorado
29
+ end
30
+
31
+ it "should cache results in memory" do
32
+ @state = State.create!(:abbreviation => "FL", :name => "Florida")
33
+ State.expects(:find).once.returns(@state)
34
+
35
+ 5.times do
36
+ State[:FL].name.should == "Florida"
37
+ end
38
+ end
39
+
40
+ it "should force cache miss in Rails test environment" do
41
+ Rails.test_environment = true
42
+
43
+ @state = State.create!(:abbreviation => "FL", :name => "Florida")
44
+ State.expects(:find).times(5).returns(@state)
45
+
46
+ 5.times do
47
+ State[:FL].name.should == "Florida"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,15 @@
1
+ pound_sterling:
2
+ code: GBP
3
+ name: Pound Sterling
4
+
5
+ euro:
6
+ code: EUR
7
+ name: Euro
8
+
9
+ us_dollar:
10
+ code: USD
11
+ name: US Dollar
12
+
13
+ renminbi:
14
+ code: CNY
15
+ name: Renminbi
@@ -0,0 +1,19 @@
1
+ arizona:
2
+ name: Arizona
3
+ abbreviation: AZ
4
+
5
+ new_york:
6
+ name: New York
7
+ abbreviation: NY
8
+
9
+ california:
10
+ name: California
11
+ abbreviation: CA
12
+
13
+ texas:
14
+ name: Texas
15
+ abbreviation: TX
16
+
17
+ colorado:
18
+ name: Colorado
19
+ abbreviation: CO
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe "an ActiveRecord model with selectable defined" do
4
+
5
+ before(:each) do
6
+ Rails.test_environment = false
7
+ State.cache_store.clear
8
+ load_fixtures
9
+ end
10
+
11
+ after(:each) do
12
+ cleanup_db
13
+ end
14
+
15
+
16
+ it "should respond to select_options" do
17
+ State.should.respond_to? :select_options
18
+ end
19
+
20
+ it "should return options for each record" do
21
+ State.select_options.length.should == State.count
22
+ State.select_options.map(&:first).should == ['Arizona','California','Colorado','New York','Texas']
23
+ end
24
+
25
+ it "should respect default scope find options" do
26
+ Currency.select_options.map(&:first).should == ['Renminbi', 'Euro', 'Pound Sterling', 'US Dollar']
27
+ end
28
+
29
+ it "should allow overriding the key and value generation" do
30
+ Currency.select_options(:code).map(&:first).should == %w( CNY EUR GBP USD )
31
+ Currency.select_options(:name, :code).should == [['Renminbi','CNY'],['Euro','EUR'],['Pound Sterling','GBP'],['US Dollar', 'USD']]
32
+ end
33
+
34
+ it "should store results in cache" do
35
+ @states = State.all
36
+ State.expects(:find).once.returns(@states)
37
+
38
+ 5.times do
39
+ State.select_options.length.should == State.count
40
+ end
41
+ end
42
+
43
+ it "should force cache miss in Rails test environment" do
44
+ Rails.test_environment = true
45
+
46
+ @states = State.all
47
+ State.expects(:find).times(5).returns(@states)
48
+
49
+ 5.times do
50
+ State.select_options.length.should == State.count
51
+ end
52
+ end
53
+
54
+ it "should not default non-column ordering" do
55
+ lambda{ CustomDisplay.select_options }.should_not raise_error
56
+ end
57
+
58
+ it "should accept defaults at the model level" do
59
+ CustomDisplayDeux.select_options.should == State.select_options(:value => :abbreviation)
60
+ end
61
+
62
+ it "should allow overriding model-level defaults" do
63
+ CustomDisplayDeux.select_options(:value => :name).should == State.select_options
64
+ end
65
+
66
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec'
2
+ begin
3
+ require 'mocha'
4
+ rescue LoadError
5
+ require "rubygems"
6
+ require 'mocha'
7
+ end
8
+
9
+ Spec::Runner.configure do |config|
10
+ config.mock_with :mocha
11
+ end
12
+
13
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
14
+ require File.join(File.dirname(__FILE__), '..', 'init')
15
+
16
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
17
+
18
+ def setup_db
19
+ ActiveRecord::Schema.verbose = false
20
+ ActiveRecord::Schema.define(:version => 1) do
21
+ create_table :states do |t|
22
+ t.string :name, :abbreviation
23
+ end
24
+
25
+ create_table :currencies do |t|
26
+ t.string :name, :code
27
+ end
28
+ end
29
+ end
30
+
31
+ def load_fixtures
32
+ %w( states currencies ).each do |fixture|
33
+ YAML.load(IO.read(File.dirname(__FILE__) + "/fixtures/#{fixture}.yml")).each do |name, attrs|
34
+ Object.const_get(fixture.singularize.classify).create!(attrs)
35
+ end
36
+ end
37
+ end
38
+
39
+ setup_db
40
+
41
+ def cleanup_db
42
+ ActiveRecord::Base.connection.tables.each do |table|
43
+ ActiveRecord::Base.connection.execute("delete from #{table}")
44
+ end
45
+ end
46
+
47
+ class Rails
48
+ cattr_accessor :test_environment
49
+
50
+ def self.env
51
+ self
52
+ end
53
+
54
+ def self.test?
55
+ @@test_environment
56
+ end
57
+ end
58
+
59
+ class State < ActiveRecord::Base
60
+ finder :abbreviation
61
+ selectable
62
+ end
63
+
64
+ class CustomDisplay < ActiveRecord::Base
65
+ selectable
66
+ set_table_name 'states'
67
+
68
+ def display_name
69
+ "custom #{name}"
70
+ end
71
+ end
72
+
73
+ class CustomDisplayDeux < ActiveRecord::Base
74
+ selectable :value => :abbreviation
75
+ set_table_name 'states'
76
+ end
77
+
78
+ class Currency < ActiveRecord::Base
79
+ selectable
80
+ default_scope :order => "code"
81
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redinger-hashdown
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Solomon White
8
+ - Christopher Redinger
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-09-24 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ type: :development
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ version:
26
+ description: hashdown is a super lightweight rails plugin that adds hash-style lookups and option lists (for generating dropdowns) to ActiveRecord models
27
+ email: redinger@gmail.com
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - README.rdoc
34
+ files:
35
+ - .gitignore
36
+ - CHANGELOG
37
+ - README.rdoc
38
+ - Rakefile
39
+ - VERSION.yml
40
+ - hashdown.gemspec
41
+ - init.rb
42
+ - lib/finder.rb
43
+ - lib/hashdown.rb
44
+ - lib/selectable.rb
45
+ - rails/init.rb
46
+ - spec/finder_spec.rb
47
+ - spec/fixtures/currencies.yml
48
+ - spec/fixtures/states.yml
49
+ - spec/selectable_spec.rb
50
+ - spec/spec_helper.rb
51
+ has_rdoc: false
52
+ homepage: http://github.com/redinger/hashdown
53
+ licenses:
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.5
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: hash-style lookups and option lists
78
+ test_files:
79
+ - spec/finder_spec.rb
80
+ - spec/selectable_spec.rb
81
+ - spec/spec_helper.rb