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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
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
@@ -0,0 +1,3 @@
1
+ module ActWithBag
2
+ VERSION = "0.2.0"
3
+ end
@@ -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
@@ -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