activerecord2-hstore 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in activerecord2-hstore.gemspec
4
+ gemspec
5
+
6
+ gem "activerecord", "~> 2.3.0", :require => "active_record"
7
+ gem "activesupport", "~> 2.3.0", :require => "active_support"
data/README.markdown ADDED
@@ -0,0 +1,162 @@
1
+ activerecord2-hstore
2
+ ====================
3
+
4
+ What is this?
5
+ -------------
6
+ This is a gem that provides some very basic functionality for working with
7
+ Postgresql's Hstore columns in ActiveRecord 2.
8
+
9
+ Documentation about the Postgresql Hstore feature can be found
10
+ **[here](http://www.postgresql.org/docs/9.1/static/hstore.html)**.
11
+
12
+ Requirements (aka boring stuff)
13
+ -------------------------------
14
+ This gem requires:
15
+
16
+ * ActiveRecord and ActiveSupport 2.3.x
17
+ * pg gem
18
+ * rspec (for running tests, duh)
19
+ * Ruby (Tested on 1.8.7 MRI, 1.9.2, and REE)
20
+ * Postgresql (Tested on 9.1)
21
+
22
+ Setup (aka more boring stuff)
23
+ -----------------------------
24
+ Install the gem like you would normally install any gem.
25
+
26
+ Enable the hstore extension on the postgres database(s) you wish to use.
27
+ Ether by creating a migration in your project that runs this SQL statement
28
+ or manually running it directly in psql console...
29
+
30
+ CREATE EXTENSION IF NOT EXISTS hstore;
31
+
32
+ Instead of me trying to hack ActiveRecord to add an actual hstore column type,
33
+ and risk breaking the universe, just manually write a migration that adds a
34
+ hstore column to your table. Here, I'll even give you an example:
35
+
36
+ ALTER TABLE my_table ADD COLUMN some_field hstore;
37
+
38
+ I recommend you add an index to that column. Supported indexes are BTREE, HASH,
39
+ GIST, and GIN. I'll leave you to handle that on your own.
40
+
41
+ Usage (aka the stuff you care about)
42
+ ------------------------------------
43
+ Now that the boring stuff is out of the way, you need to tell your model that
44
+ you have a hstore column.
45
+
46
+ Assume you have the following table:
47
+
48
+ peeps
49
+ id: integer
50
+ name: string
51
+ infos: hstore
52
+
53
+ You can tell your model infos is a hstore column thusly...
54
+
55
+ class Peep < ActiveRecord::Base
56
+ hstore_column :infos
57
+ end
58
+
59
+ What does that one line get you?
60
+
61
+ * A getter that returns the hstore column as a hash...
62
+
63
+ @peep.infos
64
+ >> {"age" => "25", "haircolor" => "black", "height" => "5'3\"", "likes" => "Cuddling while watching TV"}
65
+
66
+ * A setter that takes a hash and converts it to a hstore string (or the method can just take a hstore string)
67
+
68
+ @peeps.infos = some_hash
69
+
70
+ * These name scopes:
71
+ * infos\_has\_key (takes a string)
72
+ * infos\_has\_all\_keys (takes a string or an array of strings)
73
+ * infos\_has\_any\_keys (takes a string or an array of strings)
74
+
75
+ So what about querying the data in that colum? Well, you can always use the
76
+ standard condisions key in ActiveRecord's find method and use the proper
77
+ syntax from the Postgresql documentation. But if you're like me and like
78
+ using searchlogic, that's not an option. So in the same line in your model,
79
+ you can specifiy some keys you'd want to filter by...
80
+
81
+ class Peep < ActiveRecord::Base
82
+ hstore_column :infos, [:age, :haircolor, :likes]
83
+ end
84
+
85
+ Passing in an array of hstore keys will give you the following named scopes
86
+ to play with...
87
+
88
+ * infos\_age\_eq
89
+ * infos\_age\_neq
90
+ * infos\_age\_eq\_any
91
+ * infos\_age\_neq\_any
92
+ * infos\_age\_like
93
+ * infos\_age\_beigns\_with
94
+ * infos\_age\_ends\_with
95
+ * (Repeat list for "haircolor" and "likes")
96
+
97
+ Which means you can then do...
98
+
99
+ Peep.infos_likes_eq("Cuddling while watching TV")
100
+ Peep.searchlogic(:infos_age_neq => "23")
101
+
102
+ But Wait, There's More!
103
+ -----------------------
104
+
105
+ The gem also adds a helper method to the Hash and String objects for converting
106
+ hashes to hstore strings and back again.
107
+
108
+ These methods were originally implemented in a gem by
109
+ [softa](https://github.com/softa/activerecord-postgres-hstore) to add hstore
110
+ to ActiveReocord 3 and tweaked slightly for this gem.
111
+
112
+ Converting a hash into a hstore string that can be used to direclty store data
113
+ in a query...
114
+
115
+ {"something something" => "something", :dark => "side"}.to_hstore
116
+ >> "\"something something\"=>something,dark=>side"
117
+
118
+ Converting a hstore string that is returned from the database into a hash so
119
+ you can actually do something with it...
120
+
121
+ "\"something something\"=>something,dark=>side".from_hstore
122
+ >> {"something something" => "something", "dark" => "side"}
123
+
124
+ Note that taking a string from hstore into a hash will produce a hash where its
125
+ keys and values are all strings.
126
+
127
+
128
+ Running Tests
129
+ -------------
130
+ For the tests to run, it's assumed there is a Postgres database called
131
+ activerecord2\_hstore\_test. The specs will create a test table and populate
132
+ it with data for you. If you want to use a different database, then edit
133
+ spec/hstore\_spec.rb to your liking.
134
+
135
+ Then just run...
136
+
137
+ rake spec
138
+
139
+ Background / Why make this? / Me Rambling
140
+ -----------------------------------------
141
+ At my current employor, I'm helping to support a rather large Rails 2.3 app
142
+ (that unfortunatly will be stuck in 2.3 for quite some time) that runs on
143
+ Postgresql. The app's primary purpose is reporting on data from its data
144
+ warehouse of well... data. Because it's on Postgresql, the development team
145
+ was interested in using some of Postgresql's special features such as array
146
+ columns and hstore datatypes. We need the ability to easily take a hash
147
+ and store that as a hstore and read the column out as a hash. Also because
148
+ we're big on reporting and use searchlogic for filtering out data, we need
149
+ some way to search a hstore field for key with certain values.
150
+
151
+ To accomplish the first goal, I first needed a way to convert a Postgresql
152
+ hstore string into a Ruby hash and back to a string. I'm using the hash and
153
+ string methods from **[softa's gem](https://github.com/softa/activerecord-postgres-hstore)**
154
+ that provides hstore support for ActiveRecord 3. With those methods, I created
155
+ a way for you to tell ActiveRecord what columns are hstore columns and this
156
+ gem will override the default column getter method to return a hash and the
157
+ setter method to accept a hash which it then converts into a hstore string.
158
+
159
+ Part two of this gem is determining a way to query a hstore field. I decided
160
+ to have the gem generate searchlogic-like named scopes by sepcifying in the
161
+ model what keys in the hstore column you'll want to filter on. The gem will
162
+ create scopes in the style of "mycolumn\_key\_eq", "mycolumn\_key\_like", etc.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "activerecord2-hstore/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "activerecord2-hstore"
7
+ s.version = Activerecord2::Hstore::VERSION
8
+ s.authors = ["Tony Drake"]
9
+ s.email = ["t27duck@gmail.com"]
10
+ s.homepage = "https://github.com/t27duck/activerecord2-hstore"
11
+ s.summary = %q{Some basic support to help integrate Postgresql's HStore into a Rails 2.3 app}
12
+ s.description = %q{Allows you to mark a column in a model as a HStore column letting you pass in a hash for its setter and retrieve a hash from its getter method. Also provides a series to named scopes for easy querying of data.}
13
+
14
+ s.rubyforge_project = "activerecord2-hstore"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec", ">=2.0.0"
23
+ s.add_runtime_dependency "activerecord", "~> 2.3.0"
24
+ s.add_runtime_dependency "activesupport", "~> 2.3.0"
25
+ s.add_runtime_dependency "pg"
26
+ end
@@ -0,0 +1,24 @@
1
+ class Hash
2
+ # Generates an hstore string format. This is the format used to insert or update stuff in the database.
3
+ #
4
+ # Original implementation from:
5
+ # https://github.com/softa/activerecord-postgres-hstore/blob/master/lib/activerecord-postgres-hstore/hash.rb
6
+ def to_hstore
7
+ return "" if empty?
8
+
9
+ map { |key, value|
10
+ pair = [key, value].map { |element|
11
+ item = element.to_s.gsub(/"/, '\"')
12
+ if element.nil?
13
+ 'NULL'
14
+ elsif item =~ /[,\s=>]/ || item.blank?
15
+ '"%s"' % item
16
+ else
17
+ item
18
+ end
19
+ }
20
+
21
+ "%s=>%s" % pair
22
+ } * ","
23
+ end
24
+ end
@@ -0,0 +1,78 @@
1
+ module Hstore
2
+ module ActiveRecord
3
+ # Called when included in ActiveRecord. Extends the Extensions module.
4
+ def self.included(base)
5
+ base.extend Extensions
6
+ end
7
+
8
+ module Extensions
9
+ # Creates a series of methods and named scopes for a hstore column. This is the primary
10
+ # method you should use to invoke this gem in a model.
11
+ #
12
+ # USAGE IN A MODEL:
13
+ # class Foo < ActiveRecord::Base
14
+ # hstore_column :some_column, [:array_of_possible_keys, :you_may_want, :to_query_on]
15
+ # end
16
+ def hstore_column(column, keys=[])
17
+ create_getter_and_setter(column)
18
+ create_hstore_key_availability_scopes(column)
19
+ Array(keys).each{ |key| create_hstore_key_search_scopes(column, key) }
20
+ end
21
+
22
+ # Creates and overrides ActiveRecord's getter and setter methods for the hstore column.
23
+ # The getter returns a hash. The setter accepts and converts either a hash or a valid
24
+ # hstore string.
25
+ def create_getter_and_setter(column)
26
+ define_method column.to_sym do
27
+ read_attribute(column.to_sym).to_s.from_hstore
28
+ end
29
+
30
+ define_method "#{column}=".to_sym do |value|
31
+ value = value.is_a?(String) ? value : value.to_hstore
32
+ write_attribute(column.to_sym, value)
33
+ end
34
+ end
35
+
36
+ # Creates named scopes for the hstore column allowing you to determine if the column
37
+ # contains a given key or set of keys.
38
+ def create_hstore_key_availability_scopes(column)
39
+ named_scope "#{column}_has_key".to_sym, Proc.new{ |key|
40
+ { :conditions => ["#{column} ? :key", {:key => key}] }
41
+ }
42
+ named_scope "#{column}_has_all_keys".to_sym, Proc.new{ |keys|
43
+ { :conditions => ["#{column} ?& ARRAY[:keys]", {:keys => Array(keys)}] }
44
+ }
45
+ named_scope "#{column}_has_any_key".to_sym, Proc.new{ |keys|
46
+ { :conditions => ["#{column} ?| ARRAY[:keys]", {:keys => Array(keys)}] }
47
+ }
48
+ end
49
+
50
+ # Creates a slew of searchlogic-like named scopes to query for a key on a hstore column
51
+ def create_hstore_key_search_scopes(column, key)
52
+ named_scope "#{column}_#{key}_eq".to_sym, Proc.new{ |value|
53
+ { :conditions => ["#{column} -> '#{key}' = ?", value.to_s] }
54
+ }
55
+ named_scope "#{column}_#{key}_neq".to_sym, Proc.new{ |value|
56
+ { :conditions => ["#{column} -> '#{key}' != ?", value.to_s] }
57
+ }
58
+ named_scope "#{column}_#{key}_eq_any".to_sym, Proc.new{ |value|
59
+ { :conditions => ["#{column} -> '#{key}' IN(?)", value.map{|v| v.to_s} ] }
60
+ }
61
+ named_scope "#{column}_#{key}_neq_any".to_sym, Proc.new{ |value|
62
+ { :conditions => ["#{column} -> '#{key}' NOT IN(?)", value.map{|v| v.to_s} ] }
63
+ }
64
+ named_scope "#{column}_#{key}_like".to_sym, Proc.new{ |value|
65
+ { :conditions => ["#{column} -> '#{key}' ILIKE(?)", "%#{value.to_s}%"] }
66
+ }
67
+ named_scope "#{column}_#{key}_begins_with".to_sym, Proc.new{ |value|
68
+ { :conditions => ["#{column} -> '#{key}' ILIKE(?)", "#{value.to_s}%"] }
69
+ }
70
+ named_scope "#{column}_#{key}_ends_with".to_sym, Proc.new{ |value|
71
+ { :conditions => ["#{column} -> '#{key}' ILIKE(?)", "%#{value.to_s}"] }
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+
@@ -0,0 +1,24 @@
1
+ class String
2
+ # Generates a hash from an hstore string format.
3
+ #
4
+ # Original implementation from:
5
+ # https://github.com/softa/activerecord-postgres-hstore/blob/master/lib/activerecord-postgres-hstore/string.rb
6
+ def from_hstore
7
+ quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
8
+ unquoted_string = /[^\s=,][^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
9
+ string = /(#{quoted_string}|#{unquoted_string})/
10
+ hstore_pair = /#{string}\s*=>\s*#{string}/
11
+
12
+ token_pairs = (scan(hstore_pair)).map { |key, value| [key, value =~ /^NULL$/i ? nil : value] }
13
+ token_pairs = token_pairs.map { |key, value|
14
+ [key, value].map { |element|
15
+ case element
16
+ when nil then element
17
+ when /^"(.*)"$/ then $1.gsub(/\\(.)/, '\1')
18
+ else element.gsub(/\\(.)/, '\1')
19
+ end
20
+ }
21
+ }
22
+ Hash[ token_pairs ]
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ module Activerecord2
2
+ module Hstore
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ require "activerecord2-hstore/version"
2
+ require "activerecord2-hstore/string"
3
+ require "activerecord2-hstore/hash"
4
+ require "activerecord2-hstore/hstore"
5
+
6
+ module Activerecord2
7
+ module Hstore
8
+ # Your code goes here...
9
+ end
10
+ end
11
+
12
+ ActiveRecord::Base.send(:include, Hstore::ActiveRecord)
data/spec/hash_spec.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+
3
+ describe Hash do
4
+ describe "Converting a hash to a hstore string" do
5
+ it "#to_hstore" do
6
+ {:a=>"b"}.to_hstore.should == "a=>b"
7
+ {"a"=>"b"}.to_hstore.should == "a=>b"
8
+ {:a=>:b}.to_hstore.should == "a=>b"
9
+ {"a"=>"2"}.to_hstore.should == "a=>2"
10
+ {:a=>2}.to_hstore.should == "a=>2"
11
+ {2=>2}.to_hstore.should == "2=>2"
12
+ {"a b"=>"b"}.to_hstore.should == "\"a b\"=>b"
13
+ {"a b"=>"b c"}.to_hstore.should == "\"a b\"=>\"b c\""
14
+ {"a"=>"b c"}.to_hstore.should == "a=>\"b c\""
15
+ end
16
+
17
+ it "converts a multiball hash to a hstore string" do
18
+ all_should_match({"a"=>"b", "c"=>"d"}, [/a=>b/, /c=>d/])
19
+ all_should_match({:a=>"b", "c"=>:d}, [/a=>b/, /c=>d/])
20
+ all_should_match({"a 1"=>"b 1", "c"=>"d"}, [/\"a 1\"=>\"b 1\"/, /c=>d/])
21
+ all_should_match({"a"=>"b", "c"=>"d 1"}, [/a=>b/, /c=>\"d 1\"/])
22
+ all_should_match({"a"=>"b", "c 1"=>"d"}, [/a=>b/, /\"c 1\"=>d/])
23
+ all_should_match({:a=>:b, "c 1"=>:"d 1"}, [/a=>b/, /\"c 1\"=>\"d 1\"/])
24
+ all_should_match({"a"=>"b", :c=>:d, "e 1"=>"f 1"}, [/a=>b/, /c=>d/, /\"e 1\"=>\"f 1\"/])
25
+ end
26
+
27
+ def all_should_match(hash, expects)
28
+ expects.each do |e|
29
+ hash.to_hstore.should match(e)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,179 @@
1
+ require "spec_helper"
2
+
3
+ ActiveRecord::Base.establish_connection(
4
+ :adapter => "postgresql",
5
+ :database => "activerecord2_hstore_test",
6
+ :encoding => "unicode"
7
+ )
8
+
9
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS my_hstores")
10
+ ActiveRecord::Base.connection.create_table(:my_hstores) do |t|
11
+ t.string :label
12
+ end
13
+ ActiveRecord::Base.connection.execute("CREATE EXTENSION IF NOT EXISTS hstore")
14
+ ActiveRecord::Base.connection.execute("ALTER TABLE my_hstores ADD COLUMN some_field hstore")
15
+
16
+ class MyHstore < ActiveRecord::Base
17
+ hstore_column :some_field, [:key]
18
+ end
19
+
20
+ describe Hstore do
21
+ before(:each) do
22
+ ActiveRecord::Base.connection.increment_open_transactions
23
+ ActiveRecord::Base.connection.begin_db_transaction
24
+ end
25
+
26
+ after(:each) do
27
+ ActiveRecord::Base.connection.rollback_db_transaction
28
+ ActiveRecord::Base.connection.decrement_open_transactions
29
+ end
30
+
31
+ it "creates the correct named scopes" do
32
+ %w(eq neq eq_any neq_any like begins_with ends_with).each do |predicate|
33
+ MyHstore.should respond_to("some_field_key_#{predicate}")
34
+ end
35
+ end
36
+
37
+ describe "available methods" do
38
+ let(:subject) do
39
+ MyHstore.new
40
+ end
41
+
42
+ it "creates a getter and setter for the some_field" do
43
+ subject.should respond_to(:some_field)
44
+ subject.should respond_to(:some_field=)
45
+ end
46
+
47
+ it "uses ActiveRecord's read_attribute for the getter method" do
48
+ subject.should_receive(:read_attribute).with(:some_field).and_return("a=>b")
49
+ subject.some_field
50
+ end
51
+
52
+ describe "setter method" do
53
+ it "uses ActiveRecord's write_attribute" do
54
+ subject.should_receive(:write_attribute)
55
+ subject.some_field = {:a => :b}
56
+ end
57
+
58
+ it "can also accept a hstore string instead of a hash" do
59
+ subject.stub(:write_attribute)
60
+ subject.some_field = "a=>b"
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "querying data" do
66
+ before(:each) do
67
+ MyHstore.create( :label=> "A", :some_field => {"key" => "1"}.to_hstore )
68
+ MyHstore.create( :label=> "B", :some_field => {:key => 1, "a" => "b"}.to_hstore )
69
+ MyHstore.create( :label=> "C", :some_field => {"key" => "2"}.to_hstore )
70
+ MyHstore.create( :label=> "D", :some_field => {"key" => "3"}.to_hstore )
71
+ MyHstore.create( :label=> "E", :some_field => {"key" => "123456789"}.to_hstore )
72
+ MyHstore.create( :label=> "F", :some_field => {"c" => "x"}.to_hstore )
73
+ end
74
+
75
+ it "queries for the records containing a specific key" do
76
+ result = MyHstore.some_field_has_key("a")
77
+ result.map(&:label).should include "B"
78
+ %w(A C D E F).each do |key|
79
+ result.map(&:label).should_not include key
80
+ end
81
+ end
82
+
83
+ it "queries for the records containing a set keys" do
84
+ result = MyHstore.some_field_has_all_keys(["a", "key"])
85
+ result.map(&:label).should include "B"
86
+ %w(A C D E F).each do |key|
87
+ result.map(&:label).should_not include key
88
+ end
89
+
90
+ result = MyHstore.some_field_has_all_keys("a")
91
+ result.map(&:label).should include "B"
92
+ %w(A C D E F).each do |key|
93
+ result.map(&:label).should_not include key
94
+ end
95
+ end
96
+
97
+ it "queries for the records containing any set keys" do
98
+ result = MyHstore.some_field_has_any_key(["a", "c"])
99
+ %w(B F).each do |key|
100
+ result.map(&:label).should include key
101
+ end
102
+ %w(A C D E).each do |key|
103
+ result.map(&:label).should_not include key
104
+ end
105
+
106
+ result = MyHstore.some_field_has_any_key("a")
107
+ result.map(&:label).should include "B"
108
+ %w(A C D E F).each do |key|
109
+ result.map(&:label).should_not include key
110
+ end
111
+ end
112
+
113
+ it "queries the right data for the named scope *_eq" do
114
+ result = MyHstore.some_field_key_eq("1")
115
+ %w(A B).each do |key|
116
+ result.map(&:label).should include key
117
+ end
118
+ %w(C D E F).each do |key|
119
+ result.map(&:label).should_not include key
120
+ end
121
+ end
122
+
123
+ it "queries the right data for the named scope *_neq" do
124
+ result = MyHstore.some_field_key_neq("1")
125
+ %w(A B F).each do |key|
126
+ result.map(&:label).should_not include key
127
+ end
128
+ %w(C D E).each do |key|
129
+ result.map(&:label).should include key
130
+ end
131
+ end
132
+
133
+ it "queries the right data for the named scope *_eq_any" do
134
+ result = MyHstore.some_field_key_eq_any(["2", "3"])
135
+ %w(A B E F).each do |key|
136
+ result.map(&:label).should_not include key
137
+ end
138
+ %w(C D).each do |key|
139
+ result.map(&:label).should include key
140
+ end
141
+ end
142
+
143
+ it "queries the right data for the named scope *_neq_any" do
144
+ result = MyHstore.some_field_key_neq_any(["2", "3"])
145
+ %w(A B E).each do |key|
146
+ result.map(&:label).should include key
147
+ end
148
+ %w(C D F).each do |key|
149
+ result.map(&:label).should_not include key
150
+ end
151
+ end
152
+
153
+ it "queries the right data for the named scope *_like" do
154
+ result = MyHstore.some_field_key_like("456")
155
+ result.map(&:label).should include "E"
156
+ %w(A B C D F).each do |key|
157
+ result.map(&:label).should_not include key
158
+ end
159
+ end
160
+
161
+ it "queries the right data for the named scope *_begins_with" do
162
+ result = MyHstore.some_field_key_begins_with("123")
163
+ result.map(&:label).should include "E"
164
+ %w(A B C D F).each do |key|
165
+ result.map(&:label).should_not include key
166
+ end
167
+ end
168
+
169
+ it "queries the right data for the named scope *_ends_with" do
170
+ result = MyHstore.some_field_key_ends_with("789")
171
+ result.map(&:label).should include "E"
172
+ %w(A B C D F).each do |key|
173
+ result.map(&:label).should_not include key
174
+ end
175
+ end
176
+
177
+ end
178
+
179
+ end
@@ -0,0 +1,10 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "active_support"
5
+ require "active_record"
6
+ require "activerecord2-hstore"
7
+
8
+ RSpec.configure do |config|
9
+ # some (optional) config here
10
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ describe String do
4
+ describe "#from_hstore" do
5
+ it "handles a single key value pair" do
6
+ "a=>b".from_hstore.should == {"a" => "b"}
7
+ "\"a\"=>\"b\"".from_hstore.should == {"a" => "b"}
8
+ "\"a 1\"=>b".from_hstore.should == {"a 1" => "b"}
9
+ "\"a 1\"=>\"b 1\"".from_hstore.should == {"a 1" => "b 1"}
10
+ "1=>b".from_hstore.should == {"1" => "b"}
11
+ "1=>1".from_hstore.should == {"1" => "1"}
12
+ end
13
+
14
+ it "converts a multikeyed hstore string to a hash" do
15
+ "a=>b,c=>d".from_hstore.should == {"a" => "b", "c" => "d"}
16
+ "\"a\"=>\"b\",\"c\"=>\"d\"".from_hstore.should == {"a" => "b", "c" => "d"}
17
+ "\"a 1\"=>b,c=>d".from_hstore.should == {"a 1" => "b", "c" => "d"}
18
+ "\"a 1\"=>b,c=>\"d 1\"".from_hstore.should == {"a 1" => "b", "c" => "d 1"}
19
+ "\"a 1\"=>\"b 1\",c=>\"d 1\"".from_hstore.should == {"a 1" => "b 1", "c" => "d 1"}
20
+ "1=>b,c=>\"d 1\"".from_hstore.should == {"1" => "b", "c" => "d 1"}
21
+ end
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activerecord2-hstore
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Tony Drake
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-16 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 15
29
+ segments:
30
+ - 2
31
+ - 0
32
+ - 0
33
+ version: 2.0.0
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: activerecord
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 2
47
+ - 3
48
+ - 0
49
+ version: 2.3.0
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: activesupport
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 2
63
+ - 3
64
+ - 0
65
+ version: 2.3.0
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: pg
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ type: :runtime
81
+ version_requirements: *id004
82
+ description: Allows you to mark a column in a model as a HStore column letting you pass in a hash for its setter and retrieve a hash from its getter method. Also provides a series to named scopes for easy querying of data.
83
+ email:
84
+ - t27duck@gmail.com
85
+ executables: []
86
+
87
+ extensions: []
88
+
89
+ extra_rdoc_files: []
90
+
91
+ files:
92
+ - .gitignore
93
+ - .rspec
94
+ - Gemfile
95
+ - README.markdown
96
+ - Rakefile
97
+ - activerecord2-hstore.gemspec
98
+ - lib/activerecord2-hstore.rb
99
+ - lib/activerecord2-hstore/hash.rb
100
+ - lib/activerecord2-hstore/hstore.rb
101
+ - lib/activerecord2-hstore/string.rb
102
+ - lib/activerecord2-hstore/version.rb
103
+ - spec/hash_spec.rb
104
+ - spec/hstore_spec.rb
105
+ - spec/spec_helper.rb
106
+ - spec/string_spec.rb
107
+ homepage: https://github.com/t27duck/activerecord2-hstore
108
+ licenses: []
109
+
110
+ post_install_message:
111
+ rdoc_options: []
112
+
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
123
+ version: "0"
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: 3
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ requirements: []
134
+
135
+ rubyforge_project: activerecord2-hstore
136
+ rubygems_version: 1.8.10
137
+ signing_key:
138
+ specification_version: 3
139
+ summary: Some basic support to help integrate Postgresql's HStore into a Rails 2.3 app
140
+ test_files:
141
+ - spec/hash_spec.rb
142
+ - spec/hstore_spec.rb
143
+ - spec/spec_helper.rb
144
+ - spec/string_spec.rb