therealadam-attribute_mapper 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # AttributeMapper
2
+
3
+ AttributeMapper provides a transparent interface for mapping
4
+ symbolic representations to a column in the database of a more primitive type.
5
+ For example, rather than hardcoding values like 1 or 2 to represent that a
6
+ Ticket model's status column is "open" or "closed" you would create the
7
+ following mapping:
8
+
9
+ class Ticket < ActiveRecord::Base
10
+ map_attribute :status, :to => {:open => 1, :closed => 2}
11
+ end
12
+
13
+ You can now get and set the status column symbolically:
14
+
15
+ ticket.status = :open
16
+ ticket.status # => :open
17
+
18
+ Internally, the integer 1 will be stored in the database.
19
+
20
+ An authoritative list of the mapping is available as a class method which is the pluralized version of the attribute:
21
+
22
+ Ticket.statuses # => {:open => 1, :closed => 2}
23
+
24
+ The primitive values of the mapping can always be used to assign the column,
25
+ though the getter for the attribute will always return the higher level
26
+ symbolic representation.
27
+
28
+ ticket.status = 1
29
+ ticket.status # => :open
30
+
31
+ ## Authors
32
+
33
+ Marcel Molina, Jr., Bruce Williams and Adam Keys
34
+
35
+ Released under the MIT License (see LICENSE).
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 9
3
+ :patch: 1
4
+ :major: 0
@@ -0,0 +1,71 @@
1
+ module AttributeMapper
2
+
3
+ class << self
4
+
5
+ def included(model)
6
+ model.extend ClassMethods
7
+ model.send(:include, InstanceMethods)
8
+ end
9
+
10
+ def load
11
+ ActiveRecord::Base.send(:include, AttributeMapper)
12
+ end
13
+
14
+ end
15
+
16
+ module ClassMethods
17
+ def map_attribute(attribute, options)
18
+ mapping = options[:to]
19
+ verify_existence_of attribute
20
+ add_accessor_for attribute, mapping
21
+ override attribute
22
+ end
23
+
24
+ private
25
+ def add_accessor_for(attribute, mapping)
26
+ class_eval(<<-EVAL)
27
+ class << self
28
+ def #{attribute.to_s.pluralize}
29
+ #{mapping.inspect}
30
+ end
31
+ end
32
+ EVAL
33
+ end
34
+
35
+ def override(*args)
36
+ override_getters *args
37
+ override_setters *args
38
+ end
39
+
40
+ def override_getters(attribute)
41
+ class_eval(<<-EVAL)
42
+ def #{attribute}
43
+ self.class.#{attribute.to_s.pluralize}.invert[read_attribute(:#{attribute})]
44
+ end
45
+ EVAL
46
+ end
47
+
48
+ def override_setters(attribute)
49
+ class_eval(<<-EVAL)
50
+ def #{attribute}=(raw_value)
51
+ value = resolve_value_of :#{attribute}, raw_value
52
+ write_attribute(:#{attribute}, value)
53
+ end
54
+ EVAL
55
+ end
56
+
57
+ def verify_existence_of(attribute)
58
+ raise ArgumentError, "`#{attribute}' is not an attribute of `#{self}'" unless column_names.include?(attribute.to_s)
59
+ end
60
+ end
61
+
62
+ module InstanceMethods
63
+ private
64
+ def resolve_value_of(attribute, raw_value)
65
+ check_value = raw_value.is_a?(String) ? raw_value.to_sym : raw_value
66
+ mapping = self.class.send(attribute.to_s.pluralize)
67
+ raise ArgumentError, "`#{check_value}' not present in attribute mapping `#{mapping.inspect}'" unless mapping.to_a.flatten.include? check_value
68
+ mapping[check_value] || check_value
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,102 @@
1
+ require 'test/unit'
2
+ require 'shoulda'
3
+ require 'active_record'
4
+
5
+ require 'attribute_mapper'
6
+
7
+ AttributeMapper.load
8
+
9
+ ActiveRecord::Base.establish_connection(
10
+ :adapter => 'sqlite3',
11
+ :database => ':memory:'
12
+ )
13
+
14
+ ActiveRecord::Schema.define do
15
+ create_table :tickets do |table|
16
+ table.column :status, :integer
17
+ end
18
+ end
19
+
20
+ # Pseudo model for testing purposes
21
+ class Ticket < ActiveRecord::Base
22
+ end
23
+
24
+ class AttributeMapperTest < Test::Unit::TestCase
25
+
26
+ context "Attribute Mapper" do
27
+ setup do
28
+ Ticket.map_attribute :status, :to => mapping
29
+ end
30
+
31
+ should "set mapping for each attribute" do
32
+ assert_equal mapping[:open], Ticket.statuses[:open]
33
+ assert_equal mapping[:closed], Ticket.statuses[:closed]
34
+ end
35
+
36
+ should "override getters and setters" do
37
+ assert_nil ticket.status
38
+ assert_nothing_raised do
39
+ ticket.status = :open
40
+ end
41
+ assert_equal :open, ticket.status
42
+ assert_equal mapping[:open], ticket[:status]
43
+
44
+ assert_nothing_raised do
45
+ ticket.status = :closed
46
+ end
47
+
48
+ assert_equal :closed, ticket.status
49
+ assert_equal mapping[:closed], ticket[:status]
50
+ end
51
+
52
+ should "allow indifferent access to setters" do
53
+ assert_nothing_raised do
54
+ ticket.status = :open
55
+ end
56
+ assert_equal :open, ticket.status
57
+ assert_nothing_raised do
58
+ ticket.status = 'open'
59
+ end
60
+ assert_equal :open, ticket.status
61
+ end
62
+
63
+ should "raise an exception when trying to map to a non-existent column" do
64
+ assert_raises(ArgumentError) do
65
+ Ticket.map_attribute :this_column_does_not_exist, :to => {:i_will_fail => 1}
66
+ end
67
+ end
68
+
69
+ should "raise an exception when setting an invalid value" do
70
+ assert_raises(ArgumentError) do
71
+ ticket.status = :non_existent_value
72
+ end
73
+ end
74
+
75
+ should "allow setting a primitive value directly if the value is present in the mapping" do
76
+ ticket = Ticket.new
77
+ assert_nothing_raised do
78
+ ticket.status = mapping[:open]
79
+ end
80
+
81
+ assert_equal :open, ticket.status
82
+
83
+ assert_raises(ArgumentError) do
84
+ ticket.status = 500
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ #######
91
+ private
92
+ #######
93
+
94
+ def mapping(options = {})
95
+ {:open => 1, :closed => 2}.merge(options)
96
+ end
97
+
98
+ def ticket
99
+ @ticket ||= Ticket.new
100
+ end
101
+
102
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: therealadam-attribute_mapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.1
5
+ platform: ruby
6
+ authors:
7
+ - Marcel Molina Jr.
8
+ - Bruce Williams
9
+ - Adam Keys
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-03-10 00:00:00 -07:00
15
+ default_executable:
16
+ dependencies: []
17
+
18
+ description: Provides a transparent interface for mapping symbolic representations to a column in the database of a more primitive type.
19
+ email: adamkkeys@gmail.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - README.md
28
+ - VERSION.yml
29
+ - lib/attribute_mapper.rb
30
+ - test/attribute_mapper_test.rb
31
+ has_rdoc: true
32
+ homepage: http://github.com/therealadam/attribute_mapper
33
+ post_install_message:
34
+ rdoc_options:
35
+ - --inline-source
36
+ - --charset=UTF-8
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ requirements: []
52
+
53
+ rubyforge_project:
54
+ rubygems_version: 1.2.0
55
+ signing_key:
56
+ specification_version: 2
57
+ summary: Map symbolic types to primitive types and stash them in a column.
58
+ test_files: []
59
+