hstore_flags 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +111 -0
- data/README.md +43 -0
- data/Rakefile +16 -0
- data/hstore_flags.gemspec +20 -0
- data/lib/hstore_flags.rb +60 -0
- data/lib/hstore_flags/version.rb +3 -0
- data/spec/database.rb +17 -0
- data/spec/hstore_flags_spec.rb +59 -0
- data/spec/spec_helper.rb +12 -0
- metadata +126 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
hstore_flags (0.0.3)
|
5
|
+
activerecord (~> 3.0)
|
6
|
+
activerecord-postgres-hstore (~> 0.4)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionmailer (3.2.8)
|
12
|
+
actionpack (= 3.2.8)
|
13
|
+
mail (~> 2.4.4)
|
14
|
+
actionpack (3.2.8)
|
15
|
+
activemodel (= 3.2.8)
|
16
|
+
activesupport (= 3.2.8)
|
17
|
+
builder (~> 3.0.0)
|
18
|
+
erubis (~> 2.7.0)
|
19
|
+
journey (~> 1.0.4)
|
20
|
+
rack (~> 1.4.0)
|
21
|
+
rack-cache (~> 1.2)
|
22
|
+
rack-test (~> 0.6.1)
|
23
|
+
sprockets (~> 2.1.3)
|
24
|
+
activemodel (3.2.8)
|
25
|
+
activesupport (= 3.2.8)
|
26
|
+
builder (~> 3.0.0)
|
27
|
+
activerecord (3.2.8)
|
28
|
+
activemodel (= 3.2.8)
|
29
|
+
activesupport (= 3.2.8)
|
30
|
+
arel (~> 3.0.2)
|
31
|
+
tzinfo (~> 0.3.29)
|
32
|
+
activerecord-postgres-hstore (0.4.1)
|
33
|
+
pg
|
34
|
+
rails
|
35
|
+
rake
|
36
|
+
activeresource (3.2.8)
|
37
|
+
activemodel (= 3.2.8)
|
38
|
+
activesupport (= 3.2.8)
|
39
|
+
activesupport (3.2.8)
|
40
|
+
i18n (~> 0.6)
|
41
|
+
multi_json (~> 1.0)
|
42
|
+
arel (3.0.2)
|
43
|
+
builder (3.0.4)
|
44
|
+
diff-lcs (1.1.3)
|
45
|
+
erubis (2.7.0)
|
46
|
+
hike (1.2.1)
|
47
|
+
i18n (0.6.1)
|
48
|
+
journey (1.0.4)
|
49
|
+
json (1.7.5)
|
50
|
+
mail (2.4.4)
|
51
|
+
i18n (>= 0.4.0)
|
52
|
+
mime-types (~> 1.16)
|
53
|
+
treetop (~> 1.4.8)
|
54
|
+
mime-types (1.19)
|
55
|
+
multi_json (1.3.7)
|
56
|
+
pg (0.14.1)
|
57
|
+
polyglot (0.3.3)
|
58
|
+
rack (1.4.1)
|
59
|
+
rack-cache (1.2)
|
60
|
+
rack (>= 0.4)
|
61
|
+
rack-ssl (1.3.2)
|
62
|
+
rack
|
63
|
+
rack-test (0.6.2)
|
64
|
+
rack (>= 1.0)
|
65
|
+
rails (3.2.8)
|
66
|
+
actionmailer (= 3.2.8)
|
67
|
+
actionpack (= 3.2.8)
|
68
|
+
activerecord (= 3.2.8)
|
69
|
+
activeresource (= 3.2.8)
|
70
|
+
activesupport (= 3.2.8)
|
71
|
+
bundler (~> 1.0)
|
72
|
+
railties (= 3.2.8)
|
73
|
+
railties (3.2.8)
|
74
|
+
actionpack (= 3.2.8)
|
75
|
+
activesupport (= 3.2.8)
|
76
|
+
rack-ssl (~> 1.3.2)
|
77
|
+
rake (>= 0.8.7)
|
78
|
+
rdoc (~> 3.4)
|
79
|
+
thor (>= 0.14.6, < 2.0)
|
80
|
+
rake (0.9.2.2)
|
81
|
+
rdoc (3.12)
|
82
|
+
json (~> 1.4)
|
83
|
+
rspec (2.11.0)
|
84
|
+
rspec-core (~> 2.11.0)
|
85
|
+
rspec-expectations (~> 2.11.0)
|
86
|
+
rspec-mocks (~> 2.11.0)
|
87
|
+
rspec-core (2.11.1)
|
88
|
+
rspec-expectations (2.11.3)
|
89
|
+
diff-lcs (~> 1.1.3)
|
90
|
+
rspec-mocks (2.11.3)
|
91
|
+
sprockets (2.1.3)
|
92
|
+
hike (~> 1.2)
|
93
|
+
rack (~> 1.0)
|
94
|
+
tilt (~> 1.1, != 1.3.0)
|
95
|
+
thor (0.16.0)
|
96
|
+
tilt (1.3.3)
|
97
|
+
treetop (1.4.12)
|
98
|
+
polyglot
|
99
|
+
polyglot (>= 0.3.1)
|
100
|
+
tzinfo (0.3.34)
|
101
|
+
|
102
|
+
PLATFORMS
|
103
|
+
ruby
|
104
|
+
|
105
|
+
DEPENDENCIES
|
106
|
+
activerecord (~> 3.0)
|
107
|
+
activerecord-postgres-hstore (~> 0.4)
|
108
|
+
hstore_flags!
|
109
|
+
pg (~> 0.14)
|
110
|
+
rake
|
111
|
+
rspec (~> 2)
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
HStore Flags
|
2
|
+
------------
|
3
|
+
|
4
|
+
integer/bit flags aggrevating you? try this.
|
5
|
+
|
6
|
+
Requirements
|
7
|
+
------------
|
8
|
+
|
9
|
+
* Rails 3.0 or greater
|
10
|
+
* Postgresql 8.4+ with contrib package
|
11
|
+
* Read [activerecord-postgres-hstore](https://raw.github.com/engageis/activerecord-postgres-hstore) for index creation
|
12
|
+
|
13
|
+
Installation
|
14
|
+
------------
|
15
|
+
|
16
|
+
TODO
|
17
|
+
|
18
|
+
Usage
|
19
|
+
-----
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# defining flags
|
23
|
+
class User < ActiveRecord::Base
|
24
|
+
hstore_flags :active, :admin
|
25
|
+
hstore_flags :customer, :vendor, :drop_ship, field: "user_type"
|
26
|
+
end
|
27
|
+
|
28
|
+
class Group < ActiveRecord::Base
|
29
|
+
hstore_flags :active, :public, :invite_only, scopes: false
|
30
|
+
end
|
31
|
+
|
32
|
+
# setting flags
|
33
|
+
u = User.new
|
34
|
+
u.active = true
|
35
|
+
u.vendor = false
|
36
|
+
|
37
|
+
# automatic scope creation
|
38
|
+
User.active.to_sql #=> SELECT * FROM users WHERE (defined(flags, 'active') IS TRUE)
|
39
|
+
User.not_drop_ship.to_sql #=> SELECT * FROM users WHERE (defined(user_type, 'drop_ship') IS NOT TRUE)
|
40
|
+
```
|
41
|
+
|
42
|
+
* `field` option defaults to `flags`
|
43
|
+
* `scopes: false` disables scope creation. though im not sure how useful that is
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
begin
|
9
|
+
Bundler.setup(:default, :development)
|
10
|
+
rescue Bundler::BundlerError => e
|
11
|
+
$stderr.puts e.message
|
12
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
13
|
+
exit e.status_code
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec::Core::RakeTask.new(:spec)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require "hstore_flags/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "hstore_flags"
|
6
|
+
s.version = HStoreFlags::VERSION
|
7
|
+
s.summary = "Store many boolean flags in an hstore column in PostgreSQL"
|
8
|
+
s.authors = ["Zachery Hostens"]
|
9
|
+
s.email = "zachery.hostens@countrystone.com"
|
10
|
+
s.homepage = "https://github.com/infinitysw/hstore_flags"
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.license = "MIT"
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
|
15
|
+
s.add_dependency "activerecord", "~> 3.0"
|
16
|
+
s.add_dependency "activerecord-postgres-hstore", "~> 0.4"
|
17
|
+
|
18
|
+
s.add_development_dependency "rspec"
|
19
|
+
s.add_development_dependency "pg"
|
20
|
+
end
|
data/lib/hstore_flags.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'hstore_flags/version'
|
2
|
+
require 'activerecord-postgres-hstore'
|
3
|
+
|
4
|
+
module HStoreFlags
|
5
|
+
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
|
10
|
+
protected
|
11
|
+
def set_hstore_flag_field(field, flag, value)
|
12
|
+
new_val = TRUE_VALUES.include?(value)
|
13
|
+
old_val = self.send(flag)
|
14
|
+
return if new_val == old_val
|
15
|
+
|
16
|
+
if defined? changed_attributes
|
17
|
+
send(:changed_attributes).merge!(flag.to_s => old_val)
|
18
|
+
end
|
19
|
+
|
20
|
+
if new_val
|
21
|
+
self[field] = (self[field] || {}).merge({flag.to_s => true.to_s})
|
22
|
+
else
|
23
|
+
self[field] && self[field].delete(flag.to_s)
|
24
|
+
end
|
25
|
+
send("#{field}_will_change!")
|
26
|
+
new_val
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
def hstore_flags(*args)
|
32
|
+
opts = args.last.is_a?(Hash) ? args.pop.dup : {}
|
33
|
+
field = opts[:field] || "flags"
|
34
|
+
table_field = "#{self.table_name}." + field
|
35
|
+
|
36
|
+
args.each do |flag|
|
37
|
+
define_method("#{flag}") {(self[field] || {})[flag.to_s] == "true"}
|
38
|
+
define_method("#{flag}?") {(self[field] || {})[flag.to_s] == "true"}
|
39
|
+
define_method("#{flag}=") {|val| set_hstore_flag_field(field, flag, val)}
|
40
|
+
|
41
|
+
unless opts[:scopes] == false
|
42
|
+
scope "#{flag}", where("defined(#{table_field}, '#{flag}') IS TRUE")
|
43
|
+
scope "not_#{flag}", where("defined(#{table_field}, '#{flag}') IS NOT TRUE")
|
44
|
+
|
45
|
+
class_eval <<-EVAL
|
46
|
+
def self.#{flag}_condition
|
47
|
+
"(defined(#{table_field}, '#{flag}') IS TRUE)"
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.not_#{flag}_condition
|
51
|
+
"(defined(#{table_field}, '#{flag}') IS NOT TRUE)"
|
52
|
+
end
|
53
|
+
EVAL
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
ActiveRecord::Base.send(:include, HStoreFlags)
|
data/spec/database.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
# connect
|
4
|
+
ActiveRecord::Base.establish_connection(
|
5
|
+
adapter: 'postgresql',
|
6
|
+
database: 'testing')
|
7
|
+
|
8
|
+
ActiveRecord::Base.connection.execute("CREATE EXTENSION IF NOT EXISTS hstore")
|
9
|
+
|
10
|
+
ActiveRecord::Schema.define(version: 1) do
|
11
|
+
execute "DROP TABLE IF EXISTS users"
|
12
|
+
|
13
|
+
create_table :users do |t|
|
14
|
+
t.column :flags, :hstore
|
15
|
+
t.column :more_flags, :hstore
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class User < ActiveRecord::Base
|
4
|
+
hstore_flags :fighter, :lover
|
5
|
+
end
|
6
|
+
|
7
|
+
class UserNoScopes < ActiveRecord::Base
|
8
|
+
self.table_name = "users"
|
9
|
+
hstore_flags :fighter, :lover, :referee, scopes: false
|
10
|
+
end
|
11
|
+
|
12
|
+
class UserMultiFlags < ActiveRecord::Base
|
13
|
+
self.table_name = "users"
|
14
|
+
hstore_flags :fighter, :lover, :referee
|
15
|
+
hstore_flags :drinker, :smoker, :bartender, field: "more_flags"
|
16
|
+
end
|
17
|
+
|
18
|
+
describe HStoreFlags do
|
19
|
+
it "creates accessors for flags" do
|
20
|
+
u = User.new(fighter: true)
|
21
|
+
expect(u.fighter).to eq(true)
|
22
|
+
expect(u.fighter?).to eq(true)
|
23
|
+
expect(u.lover).to eq(false)
|
24
|
+
expect(u.lover?).to eq(false)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "creates scopes without scopes: false" do
|
28
|
+
expect(User).to respond_to(:fighter)
|
29
|
+
expect(User).to respond_to(:not_fighter)
|
30
|
+
expect(User).to respond_to(:lover)
|
31
|
+
expect(User).to respond_to(:not_lover)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "does not create scopes with scopes: false" do
|
35
|
+
expect(UserNoScopes).not_to respond_to(:fighter)
|
36
|
+
expect(UserNoScopes).not_to respond_to(:not_fighter)
|
37
|
+
expect(UserNoScopes).not_to respond_to(:lover)
|
38
|
+
expect(UserNoScopes).not_to respond_to(:not_lover)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "creates proper scopes when no field is defined" do
|
42
|
+
expect(User.fighter.to_sql).to match(/defined\(users.flags, 'fighter'\) IS TRUE/)
|
43
|
+
expect(User.not_fighter.to_sql).to match(/defined\(users.flags, 'fighter'\) IS NOT TRUE/)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "creates proper scopes when field is defined" do
|
47
|
+
expect(UserMultiFlags.drinker.to_sql).to match(/defined\(users.more_flags, 'drinker'\) IS TRUE/)
|
48
|
+
expect(UserMultiFlags.not_drinker.to_sql).to match(/defined\(users.more_flags, 'drinker'\) IS NOT TRUE/)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "updates changes with new bit values" do
|
52
|
+
u = User.new
|
53
|
+
expect(u.changes[:fighter]).to eq(nil)
|
54
|
+
u.fighter = true
|
55
|
+
expect(u.changes[:fighter]).to eq([false, true])
|
56
|
+
u.fighter = false
|
57
|
+
expect(u.changes[:fighter]).to eq([true, false]) # this is wrong, it should disappear
|
58
|
+
end
|
59
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
if ENV['VERSION']
|
3
|
+
gem 'activesupport', ENV['VERSION']
|
4
|
+
gem 'activerecord', ENV['VERSION']
|
5
|
+
end
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
8
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
9
|
+
|
10
|
+
require 'active_record'
|
11
|
+
require 'hstore_flags'
|
12
|
+
require 'database'
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hstore_flags
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Zachery Hostens
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activerecord-postgres-hstore
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0.4'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0.4'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pg
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description:
|
79
|
+
email: zachery.hostens@countrystone.com
|
80
|
+
executables: []
|
81
|
+
extensions: []
|
82
|
+
extra_rdoc_files: []
|
83
|
+
files:
|
84
|
+
- .gitignore
|
85
|
+
- Gemfile
|
86
|
+
- Gemfile.lock
|
87
|
+
- README.md
|
88
|
+
- Rakefile
|
89
|
+
- hstore_flags.gemspec
|
90
|
+
- lib/hstore_flags.rb
|
91
|
+
- lib/hstore_flags/version.rb
|
92
|
+
- spec/database.rb
|
93
|
+
- spec/hstore_flags_spec.rb
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
homepage: https://github.com/infinitysw/hstore_flags
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
hash: 1999031587017127090
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
hash: 1999031587017127090
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 1.8.23
|
123
|
+
signing_key:
|
124
|
+
specification_version: 3
|
125
|
+
summary: Store many boolean flags in an hstore column in PostgreSQL
|
126
|
+
test_files: []
|