dynattribs 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/.gitignore +15 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +81 -0
- data/Rakefile +15 -0
- data/dynattribs.gemspec +23 -0
- data/lib/dynattribs.rb +83 -0
- data/lib/dynattribs/version.rb +3 -0
- data/spec/dummy/db/migrate/00001_create_my_test_class.rb +9 -0
- data/spec/dummy/my_test_class.rb +8 -0
- data/spec/dynattribs_spec.rb +25 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/active_record.rb +3 -0
- data/travis.yml +9 -0
- metadata +110 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2013 James P. McGrath
|
|
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.rdoc
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
= Dynattribs (Dynamic Attributes)
|
|
2
|
+
Dynattribs makes it easy to declare dynamic attributes in ActiveRecord classes.
|
|
3
|
+
|
|
4
|
+
== Overview
|
|
5
|
+
|
|
6
|
+
The Dynattribs Gem (Dyanmic Attributes) provide a database backed attributes to
|
|
7
|
+
ActiveRecord::Base classes, without having to declare table columns for each
|
|
8
|
+
attribute. A bit of NoSQL data flexibility for traditional database backed
|
|
9
|
+
ActiveRecord classes.
|
|
10
|
+
|
|
11
|
+
The dynamic attributes are stored as a JSON encoded Hash, and can be
|
|
12
|
+
persisted into any field that can store text data.
|
|
13
|
+
|
|
14
|
+
== Installation
|
|
15
|
+
|
|
16
|
+
You can use the Dynattribs in your Rails project by including the following in your Gemfile:
|
|
17
|
+
|
|
18
|
+
gem 'dynattribs'
|
|
19
|
+
|
|
20
|
+
== Usage
|
|
21
|
+
|
|
22
|
+
To use Dynattribs you need to include the mixin in your class definition, preferably at the top.
|
|
23
|
+
|
|
24
|
+
To define the names of the dynamic attributes use the "dynamic_attr_accessor"
|
|
25
|
+
method. This method takes two of more arguments. The first argument is the name
|
|
26
|
+
of the database field that the dynamic attributes will be persisted to. The other
|
|
27
|
+
arguments are the names of the dynamic attributes. It is meant to be used in a
|
|
28
|
+
similar way to the familure "attr_accessor" method
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
=== Example
|
|
32
|
+
The following example defines a dynamic "info" field for the MyClass class, with
|
|
33
|
+
the new info field's data being persisted to the "extra_data" database field.
|
|
34
|
+
|
|
35
|
+
class MyClass < < ActiveRecord::Base
|
|
36
|
+
include Dynattribs
|
|
37
|
+
|
|
38
|
+
dynamic_attr_accessor :extra_data, :info
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
=== Database
|
|
42
|
+
The dynamic attributes are stored converted to a JSON encoded string before storing
|
|
43
|
+
to the nominated database field. Therefore, you will need to add a string column
|
|
44
|
+
to the table of any class you wish to add dynamic attributes too.
|
|
45
|
+
|
|
46
|
+
A String field would work, but a "text" field would be best due to the large amount
|
|
47
|
+
of data that could be stored in the dynamic attributes.
|
|
48
|
+
|
|
49
|
+
To add the new column, create a migration, e.g.
|
|
50
|
+
|
|
51
|
+
rails g migration add_model_dynamic_attribute
|
|
52
|
+
|
|
53
|
+
And modify the migration to look something like this:
|
|
54
|
+
|
|
55
|
+
class AddModelDynamicAttribute < ActiveRecord::Migration
|
|
56
|
+
def change
|
|
57
|
+
add_column :models, :dynamic_attribs, :text
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
== In The Wild
|
|
62
|
+
|
|
63
|
+
Dynattribs is used in a number of production systems:
|
|
64
|
+
|
|
65
|
+
{Capstory - Private Group Photo Albums }[http://www.capstory.com/]
|
|
66
|
+
|
|
67
|
+
{Authic - A Local shopping Sales Notification Service}[http://www.authic.com]
|
|
68
|
+
|
|
69
|
+
If you are using Dynattribs in your project and would like to be added to this list, please get in touch!
|
|
70
|
+
|
|
71
|
+
== Contributing
|
|
72
|
+
|
|
73
|
+
Contributions are very welcome. Please ensure all pull requests include suitable test coverage and all tests are passing.
|
|
74
|
+
|
|
75
|
+
== Authors
|
|
76
|
+
|
|
77
|
+
* {James McGrath}[https://github.com/jpmcgrath]
|
|
78
|
+
|
|
79
|
+
== Licence
|
|
80
|
+
|
|
81
|
+
This code is licensed under the MIT license. See MIT-LICENCE for more details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'bundler'
|
|
2
|
+
require 'rspec/core/rake_task'
|
|
3
|
+
require 'rdoc/task'
|
|
4
|
+
Bundler::GemHelper.install_tasks
|
|
5
|
+
|
|
6
|
+
task :default => :spec
|
|
7
|
+
RSpec::Core::RakeTask.new
|
|
8
|
+
|
|
9
|
+
RDoc::Task.new :rdoc do |rdoc|
|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
11
|
+
rdoc.title = 'Dynattribs'
|
|
12
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
15
|
+
end
|
data/dynattribs.gemspec
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require File.expand_path("../lib/dynattribs/version", __FILE__)
|
|
2
|
+
|
|
3
|
+
# Provide a simple gemspec so you can easily use your enginex
|
|
4
|
+
# project in your rails apps through git.
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "dynattribs"
|
|
7
|
+
s.summary = "Dynattribs makes it easy to declare dynamic attributes in ActiveRecord classes."
|
|
8
|
+
s.description = "The Dynattribs Gem (Dyanmic Attributes) provide a database backed attributes to ActiveRecord::Base classes, without having to declare table columns for each attribute. A bit of NoSQL data flexibility for traditional database backed ActiveRecord classes."
|
|
9
|
+
s.files = `git ls-files`.split("\n")
|
|
10
|
+
s.version = Dynattribs::VERSION
|
|
11
|
+
s.platform = Gem::Platform::RUBY
|
|
12
|
+
s.authors = [ "James P. McGrath" ]
|
|
13
|
+
s.email = [ "gems@jamespmcgrath.com" ]
|
|
14
|
+
s.homepage = "http://jamespmcgrath.com/projects/dynattribs"
|
|
15
|
+
s.rubyforge_project = "dynattribs"
|
|
16
|
+
s.required_rubygems_version = "> 1.3.6"
|
|
17
|
+
#s.add_dependency "rails", ">= 3.0.7"
|
|
18
|
+
s.add_development_dependency "rspec"
|
|
19
|
+
s.add_development_dependency "sqlite3"
|
|
20
|
+
s.add_development_dependency "activerecord"
|
|
21
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
|
22
|
+
s.require_path = 'lib'
|
|
23
|
+
end
|
data/lib/dynattribs.rb
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module Dynattribs
|
|
2
|
+
|
|
3
|
+
############################################################
|
|
4
|
+
#
|
|
5
|
+
# PARSE AND ENCODE THE DYNAMIC FIELD DATA
|
|
6
|
+
# the data is stored to a field defined by "dynamic_attributes_backing_field_name"
|
|
7
|
+
#
|
|
8
|
+
############################################################
|
|
9
|
+
|
|
10
|
+
# parse and return the json encoded values from the encoded
|
|
11
|
+
# data stored in the nominated attribute
|
|
12
|
+
def mapped_data
|
|
13
|
+
return {} if self[dynamic_attributes_backing_field_name].nil?
|
|
14
|
+
JSON.parse(self[dynamic_attributes_backing_field_name])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# JSON encode and store a hash of attributes
|
|
18
|
+
def mapped_data=hash
|
|
19
|
+
self[dynamic_attributes_backing_field_name] = hash.to_json
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
############################################################
|
|
23
|
+
#
|
|
24
|
+
# GENERAL GET/SET METHODS
|
|
25
|
+
#
|
|
26
|
+
############################################################
|
|
27
|
+
|
|
28
|
+
# a general method for retieving a named attribute
|
|
29
|
+
# from the encoded data
|
|
30
|
+
def get_dynamic_attr(attr_name)
|
|
31
|
+
mapped_data[attr_name]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# a general method to set the value of the named
|
|
35
|
+
# attribute in the data map
|
|
36
|
+
def set_dynamic_attr(attr_name, value)
|
|
37
|
+
data_map = self.mapped_data
|
|
38
|
+
data_map[attr_name] = value
|
|
39
|
+
self.mapped_data = data_map
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
############################################################
|
|
43
|
+
#
|
|
44
|
+
# CLASS METHODS
|
|
45
|
+
#
|
|
46
|
+
############################################################
|
|
47
|
+
|
|
48
|
+
# this bit of ma allows us to "include" class methods (instead of
|
|
49
|
+
# the normal "extend")with the mixin.
|
|
50
|
+
# which is needed as the dynamic_attr_accessor method needs
|
|
51
|
+
# to be invoked as a class method as it is used in the class
|
|
52
|
+
# definition, rather than from within a instance method
|
|
53
|
+
def self.included(base)
|
|
54
|
+
base.extend(ClassMethods)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
module ClassMethods
|
|
58
|
+
|
|
59
|
+
# takes two or more arguments, first arg is the name of the database
|
|
60
|
+
# field that backs the dynamic fields data hash.
|
|
61
|
+
# the other arguments are used to create getter/setter methods of
|
|
62
|
+
# the arguments name.
|
|
63
|
+
def dynamic_attr_accessor(*args)
|
|
64
|
+
|
|
65
|
+
# the first element in the array is the name of the field
|
|
66
|
+
# used to store the json encoded dynamic attribute data
|
|
67
|
+
dynamic_attributes_backing_field_name = args.shift
|
|
68
|
+
# create a method to access this extra data field name
|
|
69
|
+
self.class_eval("def dynamic_attributes_backing_field_name;'#{dynamic_attributes_backing_field_name}';end") if !dynamic_attributes_backing_field_name.empty?
|
|
70
|
+
|
|
71
|
+
# iterate through the rest of the arguments and create
|
|
72
|
+
# a getter and setter method of each of the desired dynamic attributes
|
|
73
|
+
args.each do |arg|
|
|
74
|
+
# getter - creates a wrapper for the get_dynamic_attr method
|
|
75
|
+
self.class_eval("def #{arg};get_dynamic_attr('#{arg}');end")
|
|
76
|
+
|
|
77
|
+
# setter - creates a wrapper for the set_dynamic_attr method
|
|
78
|
+
self.class_eval("def #{arg}=(val);set_dynamic_attr('#{arg}', val); end")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe Dynattribs do
|
|
5
|
+
|
|
6
|
+
it "should store and load dynamic attributes" do
|
|
7
|
+
my_test_class = MyTestClass.new
|
|
8
|
+
|
|
9
|
+
my_test_class.info = "This will be stored into info"
|
|
10
|
+
my_test_class.is_bool = false
|
|
11
|
+
my_test_class.age = 24
|
|
12
|
+
my_test_class.tested_at = Time.now
|
|
13
|
+
|
|
14
|
+
my_test_class.save.should == true
|
|
15
|
+
|
|
16
|
+
loaded_object = MyTestClass.find(my_test_class.id)
|
|
17
|
+
|
|
18
|
+
loaded_object.nil?.should == false
|
|
19
|
+
|
|
20
|
+
loaded_object.info.should == my_test_class.info
|
|
21
|
+
loaded_object.is_bool.should == my_test_class.is_bool
|
|
22
|
+
loaded_object.age.should == my_test_class.age
|
|
23
|
+
loaded_object.tested_at.should == my_test_class.tested_at
|
|
24
|
+
end
|
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Configure Rails Envinronment
|
|
2
|
+
ENV["RAILS_ENV"] = "test"
|
|
3
|
+
|
|
4
|
+
require 'dynattribs'
|
|
5
|
+
require File.expand_path("../dummy/my_test_class.rb", __FILE__)
|
|
6
|
+
|
|
7
|
+
# Run any available migration
|
|
8
|
+
ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
|
data/travis.yml
ADDED
metadata
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: dynattribs
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- James P. McGrath
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-03-13 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rspec
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: sqlite3
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: activerecord
|
|
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
|
+
description: The Dynattribs Gem (Dyanmic Attributes) provide a database backed attributes
|
|
63
|
+
to ActiveRecord::Base classes, without having to declare table columns for each
|
|
64
|
+
attribute. A bit of NoSQL data flexibility for traditional database backed ActiveRecord
|
|
65
|
+
classes.
|
|
66
|
+
email:
|
|
67
|
+
- gems@jamespmcgrath.com
|
|
68
|
+
executables: []
|
|
69
|
+
extensions: []
|
|
70
|
+
extra_rdoc_files: []
|
|
71
|
+
files:
|
|
72
|
+
- .gitignore
|
|
73
|
+
- Gemfile
|
|
74
|
+
- MIT-LICENSE
|
|
75
|
+
- README.rdoc
|
|
76
|
+
- Rakefile
|
|
77
|
+
- dynattribs.gemspec
|
|
78
|
+
- lib/dynattribs.rb
|
|
79
|
+
- lib/dynattribs/version.rb
|
|
80
|
+
- spec/dummy/db/migrate/00001_create_my_test_class.rb
|
|
81
|
+
- spec/dummy/my_test_class.rb
|
|
82
|
+
- spec/dynattribs_spec.rb
|
|
83
|
+
- spec/spec_helper.rb
|
|
84
|
+
- spec/support/active_record.rb
|
|
85
|
+
- travis.yml
|
|
86
|
+
homepage: http://jamespmcgrath.com/projects/dynattribs
|
|
87
|
+
licenses: []
|
|
88
|
+
post_install_message:
|
|
89
|
+
rdoc_options: []
|
|
90
|
+
require_paths:
|
|
91
|
+
- lib
|
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
|
+
none: false
|
|
94
|
+
requirements:
|
|
95
|
+
- - ! '>='
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
|
+
none: false
|
|
100
|
+
requirements:
|
|
101
|
+
- - ! '>'
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: 1.3.6
|
|
104
|
+
requirements: []
|
|
105
|
+
rubyforge_project: dynattribs
|
|
106
|
+
rubygems_version: 1.8.24
|
|
107
|
+
signing_key:
|
|
108
|
+
specification_version: 3
|
|
109
|
+
summary: Dynattribs makes it easy to declare dynamic attributes in ActiveRecord classes.
|
|
110
|
+
test_files: []
|