act_with_bag 0.2.0
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 +4 -0
- data/Gemfile +2 -0
- data/README +51 -0
- data/Rakefile +24 -0
- data/act_with_bag.gemspec +26 -0
- data/lib/act_with_bag/version.rb +3 -0
- data/lib/act_with_bag.rb +113 -0
- data/test/bag_test.rb +65 -0
- data/test/test_helper.rb +16 -0
- metadata +67 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
ActWithBag
|
2
|
+
==========
|
3
|
+
|
4
|
+
In Gemfile:
|
5
|
+
gem 'act_with_bag'
|
6
|
+
|
7
|
+
Bag helps when fields in a table are not yet settled down
|
8
|
+
or when many fields without business logic are required.
|
9
|
+
|
10
|
+
Install one bag in a table to collect many fields.
|
11
|
+
Additional fields or removal of them are easy.
|
12
|
+
No migration is required for new fields.
|
13
|
+
|
14
|
+
Keep in mind that the collection is kept in a YAML bag, i.e.
|
15
|
+
SQL commands can't access the fields.
|
16
|
+
|
17
|
+
Boolean and Date fields require explicit typing, others are
|
18
|
+
treated as string.
|
19
|
+
|
20
|
+
Technical background: getters and putters are injected into models.
|
21
|
+
If baggies of type :date are being used then
|
22
|
+
params must be corrected before an update_attributes.
|
23
|
+
Warning: :date fields are not well integrated; avoid them.
|
24
|
+
|
25
|
+
|
26
|
+
Example
|
27
|
+
=======
|
28
|
+
|
29
|
+
In model:
|
30
|
+
class Order < ActiveRecord::Base
|
31
|
+
add_to_bag :name, :color, :description,
|
32
|
+
{:active => :boolean},
|
33
|
+
{:paused_at => :date}
|
34
|
+
|
35
|
+
In controller:
|
36
|
+
class OrdersController < ApplicationController
|
37
|
+
def create
|
38
|
+
params = Order.merge({}, self.params) # only if type :date is being used
|
39
|
+
@order = Order.new(params[:order])
|
40
|
+
|
41
|
+
def update
|
42
|
+
@order = Order.find(params[:id])
|
43
|
+
params = Order.merge(@order.bag, self.params) # only if type :date is being used
|
44
|
+
|
45
|
+
Test
|
46
|
+
====
|
47
|
+
|
48
|
+
rake
|
49
|
+
|
50
|
+
|
51
|
+
Copyright (c) 2009-2011 [Dittmar Krall], released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
desc 'Default: run unit tests.'
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
desc 'Test the act_with_bag plugin.'
|
10
|
+
Rake::TestTask.new(:test) do |t|
|
11
|
+
t.libs << 'lib'
|
12
|
+
t.libs << 'test'
|
13
|
+
t.pattern = 'test/**/*_test.rb'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Generate documentation for the act_with_bag plugin.'
|
18
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
19
|
+
rdoc.rdoc_dir = 'rdoc'
|
20
|
+
rdoc.title = 'act_with_bag'
|
21
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
22
|
+
rdoc.rdoc_files.include('README')
|
23
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "act_with_bag/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "act_with_bag"
|
7
|
+
s.version = ActWithBag::VERSION
|
8
|
+
s.authors = ["matique"]
|
9
|
+
s.email = ["dittmar.krall@matique.de"]
|
10
|
+
s.homepage = "http://www.matique.de"
|
11
|
+
s.summary = %q{act_with_bag (baggies) gem}
|
12
|
+
s.description = %q{Add a bag to a Rails model}
|
13
|
+
|
14
|
+
s.rubyforge_project = "act_with_bag"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
|
25
|
+
s.add_development_dependency "sqlite3"
|
26
|
+
end
|
data/lib/act_with_bag.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
class << ActiveRecord::Base
|
2
|
+
|
3
|
+
def add_to_bag(*baglets)
|
4
|
+
#p "baglets #{baglets.inspect}"
|
5
|
+
serialize :bag, Hash
|
6
|
+
|
7
|
+
self.class_eval %{
|
8
|
+
def bag=(x)
|
9
|
+
#bag changes disabled as it must be handled by Bag himself
|
10
|
+
end
|
11
|
+
}
|
12
|
+
model = model_sym
|
13
|
+
@baggies ||= {}
|
14
|
+
@baggies[model] ||= {}
|
15
|
+
baglets.each {|b|
|
16
|
+
if b.is_a?(Hash)
|
17
|
+
b.each {|baggie, type|
|
18
|
+
@baggies[model].merge!(baggie => type)
|
19
|
+
add_accessor(baggie)
|
20
|
+
}
|
21
|
+
else
|
22
|
+
@baggies[model].merge!(b => :string)
|
23
|
+
add_accessor(b)
|
24
|
+
end
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def baggies
|
29
|
+
@baggies ||= {}
|
30
|
+
@baggies[model_sym] || {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def merge(bag, params)
|
34
|
+
model = model_sym
|
35
|
+
return params unless params[model]
|
36
|
+
|
37
|
+
baggies.each {|baggie, type|
|
38
|
+
if type == :date
|
39
|
+
res, found, stopped = [], false, false
|
40
|
+
(1..3).each {|i|
|
41
|
+
p = params[model].delete("#{baggie}(#{i}i)")
|
42
|
+
break if p.nil?
|
43
|
+
found = true
|
44
|
+
stopped = true if p.empty?
|
45
|
+
res << p.to_i unless stopped
|
46
|
+
}
|
47
|
+
next unless found
|
48
|
+
## weird Timestamp, Hash and YAML problem
|
49
|
+
res = [0] if res == []
|
50
|
+
res[0] = 0 unless res[0] >= 0
|
51
|
+
|
52
|
+
value = Date.new(*res) rescue value = nil
|
53
|
+
params[model][baggie] = value
|
54
|
+
end
|
55
|
+
}
|
56
|
+
params
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def model_sym
|
61
|
+
self.to_s.underscore.to_sym
|
62
|
+
end
|
63
|
+
|
64
|
+
def free_accessor(str)
|
65
|
+
accessor = str.to_sym
|
66
|
+
return accessor unless self.method_defined?(accessor)
|
67
|
+
logger.info "** Already defined #{self.to_s}.#{accessor}"
|
68
|
+
#p "** Bag: untouched accessor '#{self.to_s}.#{accessor}'"
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def add_accessor(baggie)
|
73
|
+
#p "add_accessor #{self.to_s} #{baggie.inspect}"
|
74
|
+
accessor = free_accessor("#{baggie.to_s}")
|
75
|
+
if accessor
|
76
|
+
self.class_eval %{
|
77
|
+
def #{accessor}
|
78
|
+
res = bag && bag[:#{baggie}]
|
79
|
+
if #{self.to_s}.baggies[:#{baggie}] == :boolean
|
80
|
+
return res if res.class == FalseClass
|
81
|
+
return res if res.class == TrueClass
|
82
|
+
return res.to_i != 0
|
83
|
+
end
|
84
|
+
res
|
85
|
+
end
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
accessor = free_accessor("#{baggie.to_s}=")
|
90
|
+
if accessor
|
91
|
+
self.class_eval %{
|
92
|
+
def #{accessor}(value)
|
93
|
+
@attributes['bag'] = {} unless bag.is_a?(Hash)
|
94
|
+
self.bag.merge!(:#{baggie} => value)
|
95
|
+
end
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
return unless baggies["#{baggie}".to_sym] == :boolean
|
100
|
+
accessor = free_accessor("#{baggie.to_s}?")
|
101
|
+
if accessor
|
102
|
+
self.class_eval %{
|
103
|
+
def #{accessor}
|
104
|
+
res = bag && bag[:#{baggie}]
|
105
|
+
return res if res.class == FalseClass
|
106
|
+
return res if res.class == TrueClass
|
107
|
+
res.to_i != 0
|
108
|
+
end
|
109
|
+
}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
data/test/bag_test.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
|
4
|
+
class Order < ActiveRecord::Base
|
5
|
+
add_to_bag :field, :flag => :boolean, :at => :date
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
class BagTest < ActiveSupport::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@order = Order.new
|
13
|
+
end
|
14
|
+
|
15
|
+
test "has a bag" do
|
16
|
+
assert @order.respond_to?(:bag)
|
17
|
+
end
|
18
|
+
|
19
|
+
test "has setters and getters" do
|
20
|
+
assert @order.respond_to?(:field)
|
21
|
+
assert @order.respond_to?(:flag)
|
22
|
+
assert @order.respond_to?(:at)
|
23
|
+
|
24
|
+
assert @order.respond_to?('field=')
|
25
|
+
assert @order.respond_to?('flag=')
|
26
|
+
assert @order.respond_to?('flag?')
|
27
|
+
assert @order.respond_to?('at=')
|
28
|
+
end
|
29
|
+
|
30
|
+
test "string access to field" do
|
31
|
+
value = 'abc'
|
32
|
+
@order.field = value
|
33
|
+
assert_equal value, @order.field
|
34
|
+
assert_not_equal 'def', @order.field
|
35
|
+
end
|
36
|
+
|
37
|
+
test "date access to at" do
|
38
|
+
value = DateTime.now
|
39
|
+
@order.at = value
|
40
|
+
assert_equal value, @order.at
|
41
|
+
assert_not_equal 'def', @order.at
|
42
|
+
end
|
43
|
+
|
44
|
+
test "boolean access to flag" do
|
45
|
+
value = true
|
46
|
+
@order.flag = value
|
47
|
+
assert_equal value, @order.flag
|
48
|
+
assert @order.flag?
|
49
|
+
assert_not_equal false, @order.flag
|
50
|
+
|
51
|
+
value = false
|
52
|
+
@order.flag = value
|
53
|
+
assert_equal value, @order.flag
|
54
|
+
assert !@order.flag?
|
55
|
+
assert_not_equal true, @order.flag
|
56
|
+
end
|
57
|
+
|
58
|
+
test "bag is hidden" do
|
59
|
+
value = 'abc'
|
60
|
+
@order.field = value
|
61
|
+
@order.bag = 'bad thing'
|
62
|
+
assert_equal value, @order.field
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
ActiveRecord::Base.establish_connection({
|
6
|
+
:adapter => 'sqlite3',
|
7
|
+
:database => 'docu_test'
|
8
|
+
})
|
9
|
+
|
10
|
+
ActiveRecord::Schema.define do
|
11
|
+
create_table 'orders', :force => true do |t|
|
12
|
+
t.column 'bag', :text
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require File.dirname(__FILE__) + '/../lib/act_with_bag.rb'
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: act_with_bag
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- matique
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-20 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sqlite3
|
16
|
+
requirement: &70820700 !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: *70820700
|
25
|
+
description: Add a bag to a Rails model
|
26
|
+
email:
|
27
|
+
- dittmar.krall@matique.de
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- README
|
35
|
+
- Rakefile
|
36
|
+
- act_with_bag.gemspec
|
37
|
+
- lib/act_with_bag.rb
|
38
|
+
- lib/act_with_bag/version.rb
|
39
|
+
- test/bag_test.rb
|
40
|
+
- test/test_helper.rb
|
41
|
+
homepage: http://www.matique.de
|
42
|
+
licenses: []
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project: act_with_bag
|
61
|
+
rubygems_version: 1.8.11
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: act_with_bag (baggies) gem
|
65
|
+
test_files:
|
66
|
+
- test/bag_test.rb
|
67
|
+
- test/test_helper.rb
|