glamazon 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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: []