two_faced 0.0.2.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +41 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +120 -0
- data/Rakefile +6 -0
- data/app/models/override.rb +17 -0
- data/lib/generators/two_faced/install/install_generator.rb +24 -0
- data/lib/generators/two_faced/install/templates/migrations/1_create_overrides.rb +17 -0
- data/lib/two_faced.rb +5 -0
- data/lib/two_faced/engine.rb +10 -0
- data/lib/two_faced/hook.rb +5 -0
- data/lib/two_faced/model_extensions.rb +70 -0
- data/lib/two_faced/railtie.rb +8 -0
- data/lib/two_faced/version.rb +3 -0
- data/spec/override_spec.rb +34 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/two_faced_spec.rb +58 -0
- data/two_faced.gemspec +18 -0
- metadata +82 -0
data/.gitignore
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
|
19
|
+
.idea/.name
|
20
|
+
|
21
|
+
.idea/.rakeTasks
|
22
|
+
|
23
|
+
.idea/dictionaries/digital466.xml
|
24
|
+
|
25
|
+
.idea/two_faced.iml
|
26
|
+
|
27
|
+
.idea/vcs.xml
|
28
|
+
|
29
|
+
.idea/workspace.xml
|
30
|
+
|
31
|
+
.idea/scopes/scope_settings.xml
|
32
|
+
|
33
|
+
.idea/modules.xml
|
34
|
+
|
35
|
+
.idea/misc.xml
|
36
|
+
|
37
|
+
.idea/encodings.xml
|
38
|
+
|
39
|
+
.gitignore
|
40
|
+
|
41
|
+
.gitignore
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Kevin Horst
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# TwoFaced
|
2
|
+
|
3
|
+
You've developed a site...and a mobile site...and facebook tab. Everything pulls in the same data and is working swimmingly, until you get a call from your boss/client --
|
4
|
+
|
5
|
+
"Hi, can we use a different photo for the Facebook version of this article? Also, the title of the Parmesan Crusted Chicken Cutlets is too long for mobile, can we just call them "Cheesy Cutlets" for mobile? "
|
6
|
+
|
7
|
+
At this point you have a few options:
|
8
|
+
|
9
|
+
1. Say no. They only get one image and one title and have to deal with it. Congratulations! You've just saved yourself a hassle.
|
10
|
+
|
11
|
+
2. Add new columns like "facebook_image" and "mobile_title" for these edge cases
|
12
|
+
|
13
|
+
3. Duplicate the records for each context and scope your queries accordingly. (Recipe.where(:context => "facebook").all ) This works, but the duplication can be a pain
|
14
|
+
|
15
|
+
4. Use TwoFaced to monkey-patch your data! Only override the attributes that are different.
|
16
|
+
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Add this line to your application's Gemfile:
|
21
|
+
|
22
|
+
gem 'two_faced', :git => "git://github.com/krhorst/two_faced.git"
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle
|
27
|
+
|
28
|
+
|
29
|
+
After you install Two Faced and add it to your Gemfile, you need to run the generator:
|
30
|
+
|
31
|
+
$ rails generate two_faced:install
|
32
|
+
$ rake db:migrate
|
33
|
+
|
34
|
+
## Configuring Models
|
35
|
+
|
36
|
+
Add the following line into any model you want to be overrideable:
|
37
|
+
|
38
|
+
acts_as_overrideable
|
39
|
+
|
40
|
+
## Adding overrides with Active Admin
|
41
|
+
|
42
|
+
Add the nested attributes to the form for the resource, like so:
|
43
|
+
|
44
|
+
form do |f|
|
45
|
+
f.inputs
|
46
|
+
f.has_many :overrides do |o|
|
47
|
+
o.input :context_name
|
48
|
+
o.input :field_name, :as => :select, :collection => f.object.attribute_names
|
49
|
+
o.input :field_value
|
50
|
+
end
|
51
|
+
f.buttons
|
52
|
+
end
|
53
|
+
|
54
|
+
## Adding overrides using the nested_form gem
|
55
|
+
|
56
|
+
Add the nested fields for overrides.
|
57
|
+
|
58
|
+
<%= nested_form_for(@yourrecord) do |f| %>
|
59
|
+
|
60
|
+
## Your existing Fields
|
61
|
+
|
62
|
+
<%= f.fields_for :overrides do |o| %>
|
63
|
+
<div class="field">
|
64
|
+
<%= f.label :context_name %><br />
|
65
|
+
<%= o.text_field :context_name %><br/>
|
66
|
+
</div>
|
67
|
+
<div class="field">
|
68
|
+
<%= f.label :field_name %><br />
|
69
|
+
<%= o.select :field_name, f.object.attribute_names.map{ |value| [value, value]} %>
|
70
|
+
</div>
|
71
|
+
<div class="field">
|
72
|
+
<%= f.label :field_value %><br />
|
73
|
+
<%= o.text_field :field_value %>
|
74
|
+
</div>
|
75
|
+
<% end %>
|
76
|
+
|
77
|
+
<%= f.link_to_add 'Add Override', :overrides %>
|
78
|
+
|
79
|
+
<div class="actions">
|
80
|
+
<%= f.submit %>
|
81
|
+
</div>
|
82
|
+
<% end %>
|
83
|
+
|
84
|
+
## Adding overrides programatically
|
85
|
+
|
86
|
+
@yourrecord.overrides.create(:field_name => "name", :field_value => "New Name", :context_name => "mobile")
|
87
|
+
|
88
|
+
## Usage
|
89
|
+
|
90
|
+
You can now load up a version of your model with all overrides merged in. By default, two_faced will not overwrite the property, but will create a new method that will return the overridden property or the original property (if no override exists).
|
91
|
+
|
92
|
+
@example = ModelName.for_context("facebook").first
|
93
|
+
@example.name # Will be the original name
|
94
|
+
@example.overridden_name # Will be the overridden name
|
95
|
+
|
96
|
+
If the overwrite parameter is passed, both the original property and the overridden property will be set to the new value
|
97
|
+
|
98
|
+
@example = ModelName.for_context("facebook", :overwrite => true).first
|
99
|
+
@example.name # Will be the overridden name
|
100
|
+
@example.overridden_name # Will be the overridden name
|
101
|
+
|
102
|
+
If overwrite is set to true, it will also mark any records as read-only (to prevent saving this context-specific value back to the database). So this will give you an error:
|
103
|
+
|
104
|
+
@example = ModelName.for_context("facebook", :overwrite => true).first
|
105
|
+
@example.save # ActiveRecord::ReadOnlyRecord exception
|
106
|
+
|
107
|
+
You can also pass a custom prefix which will be used in place of "overridden". An underscore will be appended to this, and then the property name
|
108
|
+
|
109
|
+
@example = ModelName.for_context("facebook", :overwrite => true, :attribute_prefix = "custom").first
|
110
|
+
@example.name # Will be the overridden name
|
111
|
+
@example.custom_name # Will be the overridden name
|
112
|
+
|
113
|
+
|
114
|
+
## Contributing
|
115
|
+
|
116
|
+
1. Fork it
|
117
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
118
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
119
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
120
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Override < ActiveRecord::Base
|
2
|
+
attr_accessible :context_name, :field_name, :field_value, :overrideable_id, :overrideable_type
|
3
|
+
|
4
|
+
belongs_to :overrideable, :polymorphic => true
|
5
|
+
|
6
|
+
validates :field_name, :presence => true
|
7
|
+
validates :context_name, :presence => true
|
8
|
+
validate :field_name_exists_on_associated_model
|
9
|
+
|
10
|
+
def field_name_exists_on_associated_model
|
11
|
+
klass = overrideable_type.constantize
|
12
|
+
unless klass.attribute_names.include?(field_name)
|
13
|
+
errors.add(:field_name, "must be an attribute of #{overrideable_type}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module TwoFaced
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < ActiveRecord::Generators::Base
|
6
|
+
desc "Installs TwoFaced and generates the necessary migrations"
|
7
|
+
|
8
|
+
argument :name, :type => :string, :default => "create_migrations"
|
9
|
+
|
10
|
+
def self.source_root
|
11
|
+
File.expand_path("../templates", __FILE__)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def create_migrations
|
16
|
+
Dir["#{self.class.source_root}/migrations/*.rb"].sort.each do |filepath|
|
17
|
+
name = File.basename(filepath)
|
18
|
+
migration_template "migrations/#{name}", "db/migrate/#{name.gsub(/^\d+_/,'')}"
|
19
|
+
sleep 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreateOverrides < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :overrides do |t|
|
4
|
+
t.string :context_name
|
5
|
+
t.string :overrideable_type
|
6
|
+
t.integer :overrideable_id
|
7
|
+
t.string :field_name
|
8
|
+
t.text :field_value
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
add_index :overrides, :context_name
|
13
|
+
add_index :overrides, :overrideable_type
|
14
|
+
add_index :overrides, :overrideable_id
|
15
|
+
add_index :overrides, :field_name
|
16
|
+
end
|
17
|
+
end
|
data/lib/two_faced.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
module TwoFaced
|
2
|
+
|
3
|
+
module ModelExtensions
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.attr_accessible :overrides_attributes
|
7
|
+
base.has_many :overrides, :as => :overrideable, :dependent => :destroy
|
8
|
+
base.accepts_nested_attributes_for :overrides
|
9
|
+
base.after_find :get_overrides_for_context
|
10
|
+
base.extend(ClassMethods)
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
@overwrite_attribute_prefix = "overridden"
|
16
|
+
|
17
|
+
def context
|
18
|
+
@context
|
19
|
+
end
|
20
|
+
|
21
|
+
def overwrite_attribute_prefix
|
22
|
+
@overwrite_attribute_prefix
|
23
|
+
end
|
24
|
+
|
25
|
+
def overwrite_attributes?
|
26
|
+
@overwrite_attributes
|
27
|
+
end
|
28
|
+
|
29
|
+
def for_context(context, options = {})
|
30
|
+
options = {
|
31
|
+
:attribute_prefix => "overridden",
|
32
|
+
:overwrite => false
|
33
|
+
}.merge(options)
|
34
|
+
|
35
|
+
@context = context
|
36
|
+
includes(:overrides)
|
37
|
+
@overwrite_attributes = options[:overwrite]
|
38
|
+
@overwrite_attribute_prefix = options[:attribute_prefix]
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_overrides_for_context
|
46
|
+
klass = self.class
|
47
|
+
self.overrides.where("context_name" => klass.context).each do |override|
|
48
|
+
singleton_class.class_eval { attr_accessor "#{klass.overwrite_attribute_prefix}_#{override.field_name}" }
|
49
|
+
send "#{klass.overwrite_attribute_prefix}_#{override.field_name}=", override.field_value
|
50
|
+
if self.class.overwrite_attributes?
|
51
|
+
send "#{override.field_name}=", override.field_value
|
52
|
+
send "readonly!"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(method_name, *args)
|
59
|
+
prefix = "#{self.class.overwrite_attribute_prefix}_"
|
60
|
+
if method_name.to_s[prefix] != nil
|
61
|
+
original_method = method_name.to_s.sub(prefix, "")
|
62
|
+
send original_method
|
63
|
+
else
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Override do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@example_model = ModelToOverride.create({:name => "Name", :description => "Description"})
|
7
|
+
@valid_override_attributes = {
|
8
|
+
:context_name => "website",
|
9
|
+
:field_name => "name",
|
10
|
+
:field_value => "New Name" }
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should create an override given valid attributes" do
|
14
|
+
@example_model.overrides.new(@valid_override_attributes)
|
15
|
+
@example_model.should be_valid
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should not create an override without a field name" do
|
19
|
+
no_field_attributes = @valid_override_attributes.merge(:field_name => "")
|
20
|
+
@example_model.overrides.new(no_field_attributes).should_not be_valid
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not create an override without a context name" do
|
24
|
+
no_context_attributes = @valid_override_attributes.merge(:context_name => "")
|
25
|
+
@example_model.overrides.new(no_context_attributes).should_not be_valid
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not create an override if the field name does not exist on the model" do
|
29
|
+
no_field_attributes = @valid_override_attributes.merge(:field_name => "nonexistent_field")
|
30
|
+
@example_model.overrides.new(no_field_attributes).should_not be_valid
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require "rails"
|
2
|
+
require "active_record"
|
3
|
+
require "two_faced"
|
4
|
+
|
5
|
+
ActiveRecord::Migration.verbose = false
|
6
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
7
|
+
|
8
|
+
def setup_db
|
9
|
+
ActiveRecord::Schema.define(:version => 0) do
|
10
|
+
|
11
|
+
create_table :overrides do |t|
|
12
|
+
t.string :context_name
|
13
|
+
t.string :overrideable_type
|
14
|
+
t.integer :overrideable_id
|
15
|
+
t.string :field_name
|
16
|
+
t.text :field_value
|
17
|
+
|
18
|
+
t.timestamps
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table :model_to_overrides do |t|
|
22
|
+
t.string :name
|
23
|
+
t.string :description
|
24
|
+
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
setup_db
|
32
|
+
|
33
|
+
def cleanup_db
|
34
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
35
|
+
ActiveRecord::Base.connection.execute("delete from #{table}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class ModelToOverride < ActiveRecord::Base
|
40
|
+
attr_accessible :name, :description
|
41
|
+
acts_as_overrideable
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
load(File.expand_path( 'app/models/override.rb'))
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TwoFaced do
|
4
|
+
|
5
|
+
after(:each) do
|
6
|
+
cleanup_db
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@record = ModelToOverride.create(:name => "Original Name", :description => "Original Description")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should show the original name normally" do
|
14
|
+
@record.name.should eq("Original Name")
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "with mobile override added" do
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
@record.overrides.create(:field_name => "name", :field_value => "New Name", :context_name => "mobile")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should still show the original name if not scoped" do
|
24
|
+
@record.name.should eq("Original Name")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should have a different overridden_name if scoped for mobile" do
|
28
|
+
mobile_version = ModelToOverride.for_context("mobile").first
|
29
|
+
mobile_version.overridden_name.should eq("New Name")
|
30
|
+
mobile_version.name.should eq("Original Name")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should overwrite the name property if passing the overwrite parameter" do
|
34
|
+
overwritten_mobile_version = ModelToOverride.for_context("mobile", :overwrite => true).first
|
35
|
+
overwritten_mobile_version.overridden_name.should eq("New Name")
|
36
|
+
overwritten_mobile_version.name.should eq("New Name")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should give read only error if attempting to save an overridden record" do
|
40
|
+
overwritten_mobile_version = ModelToOverride.for_context("mobile", :overwrite => true).first
|
41
|
+
expect { overwritten_mobile_version.save }.to raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should show original name if override does not match scope" do
|
45
|
+
facebook_version = ModelToOverride.for_context("facebook", :overwrite => true).first
|
46
|
+
facebook_version.name.should eq("Original Name")
|
47
|
+
facebook_version.overridden_name.should eq("Original Name")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should create a property with a custom prefix" do
|
51
|
+
custom_prefixed_version = ModelToOverride.for_context("mobile", :attribute_prefix => "custom").first
|
52
|
+
custom_prefixed_version.name.should eq("Original Name")
|
53
|
+
custom_prefixed_version.custom_name.should eq("New Name")
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/two_faced.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/two_faced/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Kevin Horst"]
|
6
|
+
gem.email = ["krhorst@gmail.com"]
|
7
|
+
gem.description = "Monkey-patch your data"
|
8
|
+
gem.summary = "Add context-specific overrides to model attributes without new columns"
|
9
|
+
gem.homepage = "http://github.com/krhorst/two_faced"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "two_faced"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = TwoFaced::VERSION
|
17
|
+
gem.add_development_dependency "rspec"
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: two_faced
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2.alpha
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kevin Horst
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-12 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
|
+
description: Monkey-patch your data
|
31
|
+
email:
|
32
|
+
- krhorst@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- LICENSE
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- app/models/override.rb
|
43
|
+
- lib/generators/two_faced/install/install_generator.rb
|
44
|
+
- lib/generators/two_faced/install/templates/migrations/1_create_overrides.rb
|
45
|
+
- lib/two_faced.rb
|
46
|
+
- lib/two_faced/engine.rb
|
47
|
+
- lib/two_faced/hook.rb
|
48
|
+
- lib/two_faced/model_extensions.rb
|
49
|
+
- lib/two_faced/railtie.rb
|
50
|
+
- lib/two_faced/version.rb
|
51
|
+
- spec/override_spec.rb
|
52
|
+
- spec/spec_helper.rb
|
53
|
+
- spec/two_faced_spec.rb
|
54
|
+
- two_faced.gemspec
|
55
|
+
homepage: http://github.com/krhorst/two_faced
|
56
|
+
licenses: []
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>'
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 1.3.1
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.8.24
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Add context-specific overrides to model attributes without new columns
|
79
|
+
test_files:
|
80
|
+
- spec/override_spec.rb
|
81
|
+
- spec/spec_helper.rb
|
82
|
+
- spec/two_faced_spec.rb
|