glamazon 0.3.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/README.textile +3 -0
- data/lib/glamazon.rb +14 -0
- data/lib/glamazon/accessors.rb +12 -0
- data/lib/glamazon/associations.rb +60 -0
- data/lib/glamazon/attributes.rb +47 -0
- data/lib/glamazon/base.rb +40 -0
- data/lib/glamazon/finder.rb +37 -0
- data/lib/glamazon/json.rb +11 -0
- metadata +130 -0
data/README.textile
ADDED
data/lib/glamazon.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Glamazon
|
2
|
+
# Stevie Graham
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'yajl'
|
6
|
+
require 'i18n'
|
7
|
+
require 'active_support'
|
8
|
+
|
9
|
+
%w(accessors attributes finder json associations base).each do |file|
|
10
|
+
require File.join(File.dirname(__FILE__), 'glamazon', file)
|
11
|
+
end
|
12
|
+
|
13
|
+
Object.class_eval { def tap() yield self; self; end } unless respond_to? :tap
|
14
|
+
Object.class_eval { def try(method) send method if respond_to? method; end } unless respond_to? :try
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Glamazon
|
2
|
+
module Accessors
|
3
|
+
def attr_readonly(*attrs)
|
4
|
+
attrs.each do |attribute|
|
5
|
+
define_method "#{attribute}=" do |obj|
|
6
|
+
instance_variable_set :"@#{attribute}", obj unless instance_variable_get :"@#{attribute}"
|
7
|
+
end
|
8
|
+
attr_reader attribute
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
# For some reason constantize doesn't get included into string when you include only inflector
|
3
|
+
# I really don't want to include anymore of active_support than necessary
|
4
|
+
String.class_eval { def constantize() ActiveSupport::Inflector.constantize self end }
|
5
|
+
|
6
|
+
module Glamazon
|
7
|
+
AssociationTypeMismatch = Class.new StandardError
|
8
|
+
module Associations
|
9
|
+
def has_many(association, options = {})
|
10
|
+
klass = options[:class]
|
11
|
+
define_method association do
|
12
|
+
unless ivar = instance_variable_get(:"@__#{association}__")
|
13
|
+
instance_variable_set :"@__#{association}__", Glamazon::Associations::HasMany.new(association, self, klass, options)
|
14
|
+
else
|
15
|
+
ivar
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
def belongs_to(association, options = {})
|
20
|
+
klass = (options[:class] || association).to_s.classify
|
21
|
+
define_method(association) { instance_variable_get :"@__#{association}__" }
|
22
|
+
define_method("#{association}=") do |object|
|
23
|
+
if object.instance_of? klass.classify.constantize
|
24
|
+
instance_variable_set :"@__#{association}__", object
|
25
|
+
else
|
26
|
+
raise Glamazon::AssociationTypeMismatch.new "Object is of incorrect type. Must be an instance of #{@class}."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
alias :has_one :belongs_to
|
31
|
+
class HasMany < Array
|
32
|
+
# inherit from array because we want basic array behaviour. we just want to override Array#<< to raise as Exception if
|
33
|
+
# object being added to collection is not an instance of the expected class.
|
34
|
+
include Glamazon::Finder
|
35
|
+
def initialize(association_type, klass = nil, associated_klass = nil, options ={})
|
36
|
+
@callbacks = Hash.new { |h,k| h[k] = [] }
|
37
|
+
Hash[options.select { |k,v| k.to_s =~ /_add$/}].each { |k,v| @callbacks[k] << options[k] }
|
38
|
+
@class = klass
|
39
|
+
@associated_class = associated_klass ? associated_klass.to_s.classify.constantize : association_type.to_s.singularize.classify.constantize
|
40
|
+
super 0
|
41
|
+
end
|
42
|
+
def all
|
43
|
+
self
|
44
|
+
end
|
45
|
+
def create(attrs={})
|
46
|
+
@associated_class.create(attrs).tap { |o| self << o }
|
47
|
+
end
|
48
|
+
def <<(object)
|
49
|
+
if object.instance_of?(@associated_class)
|
50
|
+
return if include?(object)
|
51
|
+
object.send :"#{@class.class.to_s.downcase}=", @class
|
52
|
+
@callbacks[:after_add].each { |cb| cb.call @class, object }
|
53
|
+
super object
|
54
|
+
else
|
55
|
+
raise Glamazon::AssociationTypeMismatch.new "Object is of incorrect type. Must be an instance of #{@associated_class}."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
module Glamazon
|
3
|
+
module Attributes
|
4
|
+
def method_missing(meth, *args, &blk)
|
5
|
+
add_attribute(meth)
|
6
|
+
meth.to_s =~ /\=$/ ? send(meth, args.first) : send(meth)
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
attributes.inspect
|
11
|
+
end
|
12
|
+
|
13
|
+
def attributes
|
14
|
+
@attributes ||= HashWithIndifferentAccess.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](attribute)
|
18
|
+
attributes[attribute]
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(attribute, value)
|
22
|
+
attributes[attribute] = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def read_attribute(attribute)
|
26
|
+
attributes[attribute]
|
27
|
+
end
|
28
|
+
|
29
|
+
def write_attribute(attribute, value)
|
30
|
+
attributes[attribute] = value
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def add_attribute(attribute)
|
35
|
+
metaclass.class_eval do
|
36
|
+
attribute = attribute.to_s.gsub /\=$/, ''
|
37
|
+
define_method(attribute) { attributes[attribute] } unless respond_to? attribute
|
38
|
+
define_method("#{attribute}=") { |value| attributes[attribute] = value; touch } unless respond_to? "#{attribute}="
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def metaclass
|
43
|
+
class << self; self; end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Glamazon
|
2
|
+
module Base
|
3
|
+
include Glamazon::Attributes
|
4
|
+
include Glamazon::JSON
|
5
|
+
|
6
|
+
def initialize(attributes = {})
|
7
|
+
self.id = SecureRandom.uuid
|
8
|
+
attributes.each { |k,v| send "#{k}=", v }
|
9
|
+
end
|
10
|
+
|
11
|
+
def save
|
12
|
+
self.class.all << self
|
13
|
+
end
|
14
|
+
|
15
|
+
def touch
|
16
|
+
self[:updated_at] = Time.now.getutc
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def all
|
21
|
+
@__all_instances__ ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
def create(params = {})
|
25
|
+
new(params).tap { |r| r.save }
|
26
|
+
end
|
27
|
+
|
28
|
+
def destroy_all
|
29
|
+
all.clear
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.included(base)
|
35
|
+
base.extend ClassMethods
|
36
|
+
base.extend Glamazon::Accessors
|
37
|
+
base.extend Glamazon::Finder
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Glamazon
|
2
|
+
module Finder
|
3
|
+
def find(id)
|
4
|
+
find_by_id(id)
|
5
|
+
end
|
6
|
+
def method_missing(meth, *args, &blk)
|
7
|
+
# Dynamic finders, e.g. Klass.find_by_foo('bar)
|
8
|
+
a = extract_attribute_from_method_name(meth)
|
9
|
+
if /find_by_([_a-zA-Z]\w*)/.match(meth.to_s)
|
10
|
+
self.class.instance_eval do
|
11
|
+
define_method(meth) { |val| all.detect { |o| o[a] == val } }
|
12
|
+
end
|
13
|
+
send meth, args.first
|
14
|
+
elsif /find_all_by_([_a-zA-Z]\w*)/.match(meth.to_s)
|
15
|
+
self.class.instance_eval do
|
16
|
+
define_method(meth) { |val| all.select { |o| o[a] == val } }
|
17
|
+
end
|
18
|
+
send meth, args.first
|
19
|
+
elsif /find_or_create_by_([_a-zA-Z]\w*)/.match(meth.to_s)
|
20
|
+
self.class.instance_eval do
|
21
|
+
define_method(meth) do |val|
|
22
|
+
send("find_by_#{a}", val) || create(a.to_sym => val)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
send meth, args.first
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def extract_attribute_from_method_name(meth)
|
34
|
+
meth.to_s.gsub /\w+_by_/, ''
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: glamazon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Stevie Graham
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-20 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: i18n
|
16
|
+
requirement: &70176423597360 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70176423597360
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: yajl-ruby
|
27
|
+
requirement: &70176423596600 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.7.7
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70176423596600
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: activesupport
|
38
|
+
requirement: &70176423595800 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 3.1.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70176423595800
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: &70176423595220 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.6.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70176423595220
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rake
|
60
|
+
requirement: &70176423594500 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.8.7
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70176423594500
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: timecop
|
71
|
+
requirement: &70176423593840 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.3.5
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70176423593840
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: mocha
|
82
|
+
requirement: &70176423593220 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.9.8
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70176423593220
|
91
|
+
description: Plain Old Ruby Object (PORO) in memory models. Intended for use in EventMachine
|
92
|
+
server applications, desktop application, etc
|
93
|
+
email: sjtgraham@mac.com
|
94
|
+
executables: []
|
95
|
+
extensions: []
|
96
|
+
extra_rdoc_files: []
|
97
|
+
files:
|
98
|
+
- README.textile
|
99
|
+
- lib/glamazon/accessors.rb
|
100
|
+
- lib/glamazon/associations.rb
|
101
|
+
- lib/glamazon/attributes.rb
|
102
|
+
- lib/glamazon/base.rb
|
103
|
+
- lib/glamazon/finder.rb
|
104
|
+
- lib/glamazon/json.rb
|
105
|
+
- lib/glamazon.rb
|
106
|
+
homepage: http://github.com/stevegraham/glamazon
|
107
|
+
licenses: []
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.8.7
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 1.8.6
|
127
|
+
signing_key:
|
128
|
+
specification_version: 3
|
129
|
+
summary: Plain Old Ruby Object (PORO) in memory models.
|
130
|
+
test_files: []
|