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 ADDED
@@ -0,0 +1,3 @@
1
+ h1. Glamazon
2
+
3
+ ActiveRecord interface compliant In memory models.
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
@@ -0,0 +1,11 @@
1
+ module Glamazon
2
+ module JSON
3
+ def to_json
4
+ encoder.encode attributes
5
+ end
6
+
7
+ def encoder
8
+ @encoder ||= Yajl::Encoder.new
9
+ end
10
+ end
11
+ 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: []