opinionated 0.0.1

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/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rails', '>= 3.1.0'
4
+ gem 'pg'
5
+ gem 'activerecord-postgres-hstore', '>= 0.3.0'
data/Gemfile.lock ADDED
@@ -0,0 +1,91 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ actionmailer (3.2.3)
5
+ actionpack (= 3.2.3)
6
+ mail (~> 2.4.4)
7
+ actionpack (3.2.3)
8
+ activemodel (= 3.2.3)
9
+ activesupport (= 3.2.3)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ journey (~> 1.0.1)
13
+ rack (~> 1.4.0)
14
+ rack-cache (~> 1.2)
15
+ rack-test (~> 0.6.1)
16
+ sprockets (~> 2.1.2)
17
+ activemodel (3.2.3)
18
+ activesupport (= 3.2.3)
19
+ builder (~> 3.0.0)
20
+ activerecord (3.2.3)
21
+ activemodel (= 3.2.3)
22
+ activesupport (= 3.2.3)
23
+ arel (~> 3.0.2)
24
+ tzinfo (~> 0.3.29)
25
+ activerecord-postgres-hstore (0.3.0)
26
+ activerecord
27
+ rake
28
+ activeresource (3.2.3)
29
+ activemodel (= 3.2.3)
30
+ activesupport (= 3.2.3)
31
+ activesupport (3.2.3)
32
+ i18n (~> 0.6)
33
+ multi_json (~> 1.0)
34
+ arel (3.0.2)
35
+ builder (3.0.0)
36
+ erubis (2.7.0)
37
+ hike (1.2.1)
38
+ i18n (0.6.0)
39
+ journey (1.0.3)
40
+ json (1.7.3)
41
+ mail (2.4.4)
42
+ i18n (>= 0.4.0)
43
+ mime-types (~> 1.16)
44
+ treetop (~> 1.4.8)
45
+ mime-types (1.18)
46
+ multi_json (1.3.6)
47
+ pg (0.13.2)
48
+ polyglot (0.3.3)
49
+ rack (1.4.1)
50
+ rack-cache (1.2)
51
+ rack (>= 0.4)
52
+ rack-ssl (1.3.2)
53
+ rack
54
+ rack-test (0.6.1)
55
+ rack (>= 1.0)
56
+ rails (3.2.3)
57
+ actionmailer (= 3.2.3)
58
+ actionpack (= 3.2.3)
59
+ activerecord (= 3.2.3)
60
+ activeresource (= 3.2.3)
61
+ activesupport (= 3.2.3)
62
+ bundler (~> 1.0)
63
+ railties (= 3.2.3)
64
+ railties (3.2.3)
65
+ actionpack (= 3.2.3)
66
+ activesupport (= 3.2.3)
67
+ rack-ssl (~> 1.3.2)
68
+ rake (>= 0.8.7)
69
+ rdoc (~> 3.4)
70
+ thor (~> 0.14.6)
71
+ rake (0.9.2.2)
72
+ rdoc (3.12)
73
+ json (~> 1.4)
74
+ sprockets (2.1.3)
75
+ hike (~> 1.2)
76
+ rack (~> 1.0)
77
+ tilt (~> 1.1, != 1.3.0)
78
+ thor (0.14.6)
79
+ tilt (1.3.3)
80
+ treetop (1.4.10)
81
+ polyglot
82
+ polyglot (>= 0.3.1)
83
+ tzinfo (0.3.33)
84
+
85
+ PLATFORMS
86
+ ruby
87
+
88
+ DEPENDENCIES
89
+ activerecord-postgres-hstore (>= 0.3.0)
90
+ pg
91
+ rails (>= 3.1.0)
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Lantirn, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ opinionated
2
+ ===========
3
+
4
+ Adds defaults and a sensible interface to activerecord-postgres-hstore
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the opinionated gem'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the opinionated gem.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Opinionated'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,145 @@
1
+ require 'opinionated/definition'
2
+ require 'opinionated/configuration'
3
+ require 'opinionated/helpers'
4
+ require 'opinionated/hash'
5
+
6
+ module Reamaze
7
+ module Opinionated
8
+ def self.included(base)
9
+ base.send :extend, ClassMethods
10
+ end
11
+
12
+ # Make methods available to ActiveRecord in the class context
13
+ module ClassMethods
14
+ def preferences(preferential = :preferences, options = {})
15
+ send :include, InstanceMethods
16
+
17
+ preferential = Helpers.normalize(preferential)
18
+
19
+ # Create accessor methods to our configuration info
20
+ class << self
21
+ attr_accessor :preferential_configuration unless method_defined?(:preferential_configuration)
22
+ end
23
+
24
+ # Initialize the configuration to an empty hash
25
+ self.preferential_configuration = {} if self.preferential_configuration.nil?
26
+
27
+ # Redefining a preference configuration once defined should not be allowed
28
+ raise ArgumentError, "#{self} class already preferences :#{preferential} defined" if self.preferential_configuration.has_key?(preferential)
29
+
30
+ configuration = Configuration.new(self, preferential, options)
31
+ yield configuration
32
+ preferential_configuration[preferential] = configuration
33
+
34
+ # override hstore Hash with a custom Hash
35
+ class_eval do
36
+ eval(
37
+ <<-EOS
38
+ def #{preferential}
39
+ h = Reamaze::Opinionated::Hash.new self, "#{preferential}"
40
+ h.replace self["#{preferential}"].from_hstore if self["#{preferential}"]
41
+ h
42
+ end
43
+ EOS
44
+ )
45
+ end
46
+ end
47
+ end
48
+
49
+ # Make methods available to ActiveRecord models in the instance context
50
+ module InstanceMethods
51
+ # we can't use alias chaining because Rails loads method_missing dynamically
52
+ def method_missing(id, *args, &block)
53
+ self.class.preferential_configuration.keys.each do |key|
54
+ # checker
55
+ match = /#{key}_(.+)\?/.match(id.to_s)
56
+ return !!get_preferential(key, match[1], true) if match
57
+
58
+ # setter
59
+ match = /#{key}_(.+)=/.match(id.to_s)
60
+ return set_preferential key, match[1], args[0], true if match
61
+
62
+ # getter
63
+ match = /#{key}_(.+)/.match(id.to_s)
64
+ return get_preferential key, match[1], true if match
65
+ end
66
+
67
+ super
68
+ end
69
+
70
+ def set_preferential(preferential, name, value, do_preprocess = false)
71
+ preferential = Helpers.normalize(preferential)
72
+ name = Helpers.normalize(name)
73
+
74
+ # Check to make sure the preferential exists
75
+ raise ArgumentError, "Preference #{preferential} is not defined for class #{self.class}" \
76
+ unless self.class.preferential_configuration.has_key?(preferential)
77
+
78
+ configuration = self.class.preferential_configuration[preferential]
79
+ definition = configuration.definitions[name]
80
+
81
+ # Do preprocess here, type_check and validate can be done as AR validation in
82
+ value = definition.preprocess.call(value) if do_preprocess and definition and definition.has_preprocess
83
+
84
+ # Invoke the association
85
+ prefs = ::Hash[self[preferential].from_hstore] if self[preferential]
86
+
87
+ if prefs.blank?
88
+ send(preferential + '=', {name => value})
89
+ prefs = send(preferential)
90
+ else
91
+ prefs[name] = value
92
+ send(preferential + '=', prefs)
93
+ end
94
+
95
+ prefs[name]
96
+ end
97
+
98
+ def get_preferential(preferential, name, do_postprocess = false)
99
+ preferential = Helpers.normalize(preferential)
100
+ name = Helpers.normalize(name)
101
+
102
+ # Check to make sure the preferential exists
103
+ raise ArgumentError, "Preference #{preferential} not defined for class #{self.class}" \
104
+ unless self.class.preferential_configuration.has_key?(preferential)
105
+
106
+ configuration = self.class.preferential_configuration[preferential]
107
+ definition = configuration.definitions[name]
108
+
109
+ # Invoke the association
110
+ prefs = self[preferential].from_hstore if self[preferential]
111
+ prefs = {} if prefs.blank?
112
+
113
+ # Try to find what they are looking for
114
+ pref = prefs[name]
115
+
116
+ # If the pref isn't found, try to fallback on a default
117
+ if pref.blank? and definition
118
+ # TODO break all these nested if statements out into helper methods, i like prettier code
119
+ # TODO raise an exception if we don't respond to default_through or the resulting object doesn't respond to the preferential
120
+ if definition.has_default_through and respond_to?(definition.default_through) and (through = send(definition.default_through)).blank? == false
121
+ value = through.send(preferential)[name]
122
+ elsif definition.has_default_dynamic
123
+ if definition.default_dynamic.instance_of?(Proc)
124
+ value = definition.default_dynamic.call(self)
125
+ else
126
+ # TODO raise an exception if we don't respond to default_dynamic
127
+ value = send(definition.default_dynamic)
128
+ end
129
+ elsif definition.has_default
130
+ value = Marshal::load(Marshal.dump(definition.default)) # BUGFIX deep cloning default values
131
+ else
132
+ value = nil
133
+ end
134
+ else
135
+ value = pref
136
+ end
137
+
138
+ value = definition.postprocess.call(value) if do_postprocess and definition and definition.has_postprocess
139
+ value
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ ActiveRecord::Base.send :include, Reamaze::Opinionated
@@ -0,0 +1,19 @@
1
+ module Reamaze
2
+ module Opinionated
3
+ class Configuration
4
+ attr_accessor :definitions
5
+
6
+ def initialize(klass, preferential, options)
7
+ @klass = klass
8
+ @preferential = preferential
9
+ @definitions = {}
10
+ end
11
+
12
+ def define(preferential, options = {})
13
+ preferential = Helpers.normalize(preferential)
14
+ raise ArgumentError, "#{@klass} already defines preferences :#{preferential}" if @definitions.has_key?(preferential)
15
+ @definitions[preferential] = Definition.new(preferential, options)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,55 @@
1
+ module Reamaze
2
+ module Opinionated
3
+ class Definition
4
+ attr_accessor :name
5
+ attr_accessor :has_type_check, :type_check
6
+ attr_accessor :has_validate, :validate
7
+ attr_accessor :has_default, :default
8
+ attr_accessor :has_default_through, :default_through
9
+ attr_accessor :has_default_dynamic, :default_dynamic
10
+ attr_accessor :has_preprocess, :preprocess
11
+ attr_accessor :has_postprocess, :postprocess
12
+
13
+ def initialize(name, options = {})
14
+ @name = name
15
+
16
+ if options.has_key?(:type_check)
17
+ @has_type_check = true
18
+ @type_check = options[:type_check].instance_of?(Array) ? options[:type_check] : [options[:type_check]]
19
+ end
20
+
21
+ if options.has_key?(:validate)
22
+ @has_validate = true
23
+ @validate = options[:validate]
24
+ end
25
+
26
+ if options.has_key?(:default)
27
+ @has_default = true
28
+ @default = options[:default]
29
+ end
30
+
31
+ if options.has_key?(:default_through)
32
+ @has_default_through = true
33
+ @default_through = options[:default_through]
34
+ end
35
+
36
+ if options.has_key?(:default_dynamic)
37
+ @has_default_dynamic = true
38
+ @default_dynamic = options[:default_dynamic]
39
+ end
40
+
41
+ if options.has_key?(:preprocess)
42
+ @has_preprocess = true
43
+ @preprocess = options[:preprocess]
44
+ end
45
+
46
+ if options.has_key?(:postprocess)
47
+ @has_postprocess = true
48
+ @postprocess = options[:postprocess]
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,29 @@
1
+ module Reamaze
2
+ module Opinionated
3
+ class Hash < ::Hash
4
+ def initialize(owner, preferential)
5
+ @owner = owner
6
+ @preferential = preferential
7
+ end
8
+
9
+ def [] key
10
+ @owner.get_preferential @preferential, key.to_s, true
11
+ end
12
+
13
+ def []= key, value
14
+ @owner.set_preferential @preferential, key.to_s, value, true
15
+ super key.to_s, value
16
+ end
17
+
18
+ def method_missing(id, *args, &block)
19
+ match = /(.+)=$/.match id.to_s
20
+ return self[match[1]] = args[0] if match
21
+
22
+ match = /(.+)\?$/.match id.to_s
23
+ return !!self[match[1]] if match
24
+
25
+ self[id]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ module Reamaze
2
+ module Opinionated
3
+ module Helpers
4
+ # Converts give symbol to string and downcases it
5
+ def self.normalize(symbol)
6
+ symbol.to_s.downcase
7
+ end
8
+ end
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opinionated
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Lu Wang
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-05-31 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description:
22
+ email:
23
+ - lwang@reamaze.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/opinionated/configuration.rb
32
+ - lib/opinionated/definition.rb
33
+ - lib/opinionated/hash.rb
34
+ - lib/opinionated/helpers.rb
35
+ - lib/opinionated.rb
36
+ - MIT-LICENSE
37
+ - README.md
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - Rakefile
41
+ homepage: http://github.com/lunaru/opinionated
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ hash: 3
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 23
64
+ segments:
65
+ - 1
66
+ - 3
67
+ - 6
68
+ version: 1.3.6
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.8.11
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Adds defaults and a sensible interface to activerecord-postgres-hstore
76
+ test_files: []
77
+