arusarka-dynamic-active-resource 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/dynamic_active_resource.rb +21 -0
- data/lib/dynamic_active_resource/associations.rb +21 -0
- data/lib/dynamic_active_resource/associations/base.rb +23 -0
- data/lib/dynamic_active_resource/associations/belongs_to.rb +11 -0
- data/lib/dynamic_active_resource/associations/has_many.rb +17 -0
- data/lib/dynamic_active_resource/base.rb +210 -0
- data/lib/dynamic_active_resource/common_class_methods.rb +131 -0
- data/lib/dynamic_active_resource/common_dynamic_class_instance_methods.rb +38 -0
- data/lib/dynamic_active_resource/helpers.rb +33 -0
- data/lib/dynamic_active_resource/version.rb +11 -0
- metadata +11 -1
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'active_resource'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
require 'active_resource'
|
6
|
+
end
|
7
|
+
|
8
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
9
|
+
|
10
|
+
require 'dynamic_active_resource/associations'
|
11
|
+
require 'dynamic_active_resource/common_dynamic_class_instance_methods'
|
12
|
+
require 'dynamic_active_resource/common_class_methods'
|
13
|
+
require 'dynamic_active_resource/helpers'
|
14
|
+
require 'dynamic_active_resource/version'
|
15
|
+
require 'dynamic_active_resource/base'
|
16
|
+
|
17
|
+
module DynamicActiveResource
|
18
|
+
end
|
19
|
+
|
20
|
+
# shorter name
|
21
|
+
DynAR = DynamicActiveResource
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'dynamic_active_resource/associations/base'
|
2
|
+
require 'dynamic_active_resource/associations/has_many'
|
3
|
+
require 'dynamic_active_resource/associations/belongs_to'
|
4
|
+
|
5
|
+
module DynamicActiveResource
|
6
|
+
module Associations
|
7
|
+
def has_many(assosiation_sym, options = {})
|
8
|
+
h_m_association = HasMany.new(assosiation_sym, options)
|
9
|
+
associations = self.instance_variable_get(:@associations) || []
|
10
|
+
associations << h_m_association
|
11
|
+
self.instance_variable_set(:@associations, associations)
|
12
|
+
end
|
13
|
+
|
14
|
+
def belongs_to(association_sym, options = {})
|
15
|
+
b_t_association = BelongsTo.new(association_sym, options)
|
16
|
+
associations = self.instance_variable_get(:@associations) || []
|
17
|
+
associations << b_t_association
|
18
|
+
self.instance_variable_set(:@associations, associations)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DynamicActiveResource
|
2
|
+
module Associations
|
3
|
+
class Base
|
4
|
+
attr_reader :method_name
|
5
|
+
def initialize(method_name, options = {})
|
6
|
+
@method_name = method_name.to_s
|
7
|
+
class_name = options[:through] || @method_name.singularize.camelize
|
8
|
+
@associated_class_name = class_name
|
9
|
+
end
|
10
|
+
|
11
|
+
# fetches the resources for the association. requires the caller to be
|
12
|
+
# passed through self.
|
13
|
+
def resources_for(caller)
|
14
|
+
raise 'Not Implemented'
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def associated_class
|
19
|
+
eval(@associated_class_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module DynamicActiveResource
|
2
|
+
module Associations
|
3
|
+
class BelongsTo < Associations::Base
|
4
|
+
def resources_for(caller)
|
5
|
+
site_elements = caller.class.site.path.split('/')
|
6
|
+
associated_resource_id = site_elements[-1]
|
7
|
+
associated_class.find(associated_resource_id)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DynamicActiveResource
|
2
|
+
module Associations
|
3
|
+
class HasMany < Base
|
4
|
+
def set_associated_class_attributes(caller)
|
5
|
+
associated_class_site = File.join(caller.class.site.to_s, caller.class.collection_name, caller.resource_identifier)
|
6
|
+
associated_class.site = associated_class_site
|
7
|
+
associated_class.user = caller.class.user
|
8
|
+
associated_class.password = caller.class.password
|
9
|
+
end
|
10
|
+
|
11
|
+
def resources_for(caller)
|
12
|
+
set_associated_class_attributes(caller)
|
13
|
+
associated_class.find(:all)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
module DynamicActiveResource
|
2
|
+
# ActiveResource makes connecting to rest resources very easy. However it has one problem
|
3
|
+
# and a big one at that. If you try setting the authentication credentials or the site or
|
4
|
+
# collection name, element name for the class for the second time it doesn't work. E.g.
|
5
|
+
#
|
6
|
+
# class Person < ActiveResource::Base
|
7
|
+
# self.site = 'http://localhost:9090/'
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# After sometime you change it to
|
11
|
+
#
|
12
|
+
# Person.site = 'https://org-server/my_proj/'
|
13
|
+
# Person.user = 'admin'
|
14
|
+
# Person.password = 'secret'
|
15
|
+
#
|
16
|
+
# Then you do
|
17
|
+
#
|
18
|
+
# Person.find(:all) => It bombs
|
19
|
+
#
|
20
|
+
# This class provides a mechanism by which you can get rid of this problem. Extend DynamicActiveResource::Base
|
21
|
+
# class in the actual class itself. Do not extend the extended class from ActiveResource::Base.
|
22
|
+
#
|
23
|
+
# E.g.
|
24
|
+
#
|
25
|
+
# class Person < DynamicActiveResource::Base
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# set the credentials
|
29
|
+
#
|
30
|
+
# Person.site = 'http://localhost:8080'
|
31
|
+
# Person.user = 'foo'
|
32
|
+
# Person.password = 'bar'
|
33
|
+
#
|
34
|
+
# Thats it. Now create some objects
|
35
|
+
#
|
36
|
+
# asur = Person.new(:name => 'Asur', :job => 'fooling around', :status => 'Single and ready 2 mingle')
|
37
|
+
# asur.save
|
38
|
+
#
|
39
|
+
# Now change the class attributes
|
40
|
+
#
|
41
|
+
# Person.site = 'https://org-server/mingle'
|
42
|
+
# Person.collection_name = 'boring_people'
|
43
|
+
#
|
44
|
+
# Now instantiate an object
|
45
|
+
#
|
46
|
+
# rakhshas = Person.new(:name => 'Rakhshas', :job => 'eating people', :status => 'just woke up and hungry')
|
47
|
+
# rakhshas.save => Voila !!!!!!! it works
|
48
|
+
#
|
49
|
+
# CUSTOMIZATIONS
|
50
|
+
# --------------
|
51
|
+
#
|
52
|
+
# No amount of wrapping can provide very detailed customizations. Either you have a lot of methods
|
53
|
+
# that are not being used or there is hardly anything at all. To oversome this problem this module
|
54
|
+
# was written to provide only those methods which are common to most active resource objects.
|
55
|
+
# However if you want to have a little more control over your active resource objects its very easy.
|
56
|
+
# Here's how you would do it normally
|
57
|
+
#
|
58
|
+
# class Person < ActiveResource::Base
|
59
|
+
# def self.count
|
60
|
+
# find(:all).size
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# def occupation
|
64
|
+
# return job if job
|
65
|
+
# 'Unemployed'
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# To do the same thing, here's how you do it using this library
|
70
|
+
#
|
71
|
+
# class Person < DynamicActiveResource::Base
|
72
|
+
# module DynamicClassSingletonMethods
|
73
|
+
# def count
|
74
|
+
# find(:all).size
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# module DynamicClassInstanceMethods
|
79
|
+
# def occupation
|
80
|
+
# return job if job
|
81
|
+
# 'Unemployed'
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# The DynamicClassInstanceMethods will be available as instance methods in the objects created,
|
87
|
+
# DynamicClassSingletonMethods will be available as class methods in the class of the object. Also
|
88
|
+
# active resource associations are sometimes paginated. So even if you use find(:all), you get
|
89
|
+
# only the first few results. To overcome this, include in your DynamicClassSingletonMethods module
|
90
|
+
# a method called find_without_pagination. In that method route it to acitve resource find with
|
91
|
+
# proper parameters. An example of the method implementation is
|
92
|
+
#
|
93
|
+
# module DynamicClassSingletonMethods
|
94
|
+
# def find_without_pagination(*args)
|
95
|
+
# scope = args.slice!(0)
|
96
|
+
# options = args.slice!(0) || {}
|
97
|
+
# options[:params] ||= {}
|
98
|
+
# options[:params].merge!({:page => 'all'})
|
99
|
+
# # call ActiveResource::Base::find with proper options
|
100
|
+
# find(scope, options)
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# The class level find method will automatically pick up this method if defined as a method in the
|
105
|
+
# DynamicClassSingeletonMethod module else it will pass it to find.
|
106
|
+
#
|
107
|
+
# ASSOCIATIONS
|
108
|
+
# ------------
|
109
|
+
#
|
110
|
+
# This gem also provides active record like associations(highly experimental). Right now it provides only two
|
111
|
+
# associations - 1) has_many, 2) belongs_to.
|
112
|
+
#
|
113
|
+
# 1) has_many
|
114
|
+
# -----------
|
115
|
+
#
|
116
|
+
# Taking the example from above the way it should be done
|
117
|
+
#
|
118
|
+
# class Person < DynamicActiveResource::Base
|
119
|
+
# has_many :cars
|
120
|
+
#
|
121
|
+
# module DynamicClassSingletonMethods
|
122
|
+
# def count
|
123
|
+
# find(:all).size
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
# module DynamicClassInstanceMethods
|
128
|
+
# def occupation
|
129
|
+
# return job if job
|
130
|
+
# 'Unemployed'
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# def resource_identifier
|
134
|
+
# name()
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# Next a car class has to be initialized
|
140
|
+
#
|
141
|
+
# class Car < DynARBase (alias for DynamicActiveResource::Base, inbuilt in the gem)
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# set resource options only at the top level( Person in this case)
|
145
|
+
#
|
146
|
+
# Person.site = 'http://localhost:8080/'
|
147
|
+
# Person.user = 'test'
|
148
|
+
# Person.password = 'secret'
|
149
|
+
#
|
150
|
+
# associations take care of setting the site in the children classes automatically
|
151
|
+
# you will notice that an additional method resource_identifier() has been defined
|
152
|
+
# in the parent class. It would be discussed shortly.
|
153
|
+
#
|
154
|
+
# The way associations work is if you do something like
|
155
|
+
#
|
156
|
+
# person = Person.find('asur').cars it will hit the url http://localhost:8080/people/asur/cars.xml
|
157
|
+
#
|
158
|
+
# You would notice that its getting the cars for the person with name 'asur'. It does so because
|
159
|
+
# in the Person class a method called resource_identifier has been defined which says that the id
|
160
|
+
# is actually name instead of the database id. If the id attribute in the xml is set appropriately
|
161
|
+
# (to 'name' in this case) then you do not need to define the method.
|
162
|
+
#
|
163
|
+
# 2) belongs_to
|
164
|
+
# -------------
|
165
|
+
#
|
166
|
+
# Again, referring to the example above
|
167
|
+
#
|
168
|
+
# class Person < DynamicActiveResource::Base
|
169
|
+
# has_many :cars
|
170
|
+
#
|
171
|
+
# module DynamicClassSingletonMethods
|
172
|
+
# def count
|
173
|
+
# find(:all).size
|
174
|
+
# end
|
175
|
+
# end
|
176
|
+
#
|
177
|
+
# module DynamicClassInstanceMethods
|
178
|
+
# def occupation
|
179
|
+
# return job if job
|
180
|
+
# 'Unemployed'
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# def resource_identifier
|
184
|
+
# name()
|
185
|
+
# end
|
186
|
+
# end
|
187
|
+
# end
|
188
|
+
#
|
189
|
+
# Next a car class has to be initialized
|
190
|
+
#
|
191
|
+
# class Car < DynARBase (alias for DynamicActiveResource::Base)
|
192
|
+
# belongs_to :person
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# Right now belongs_to supports only assocation with a single class. After defining this you
|
196
|
+
# automatically have a method 'person' available.
|
197
|
+
#
|
198
|
+
# car = Car.find('WB1234I')
|
199
|
+
# owner = car.person
|
200
|
+
|
201
|
+
class Base < ActiveResource::Base
|
202
|
+
def self.inherited(subclass)
|
203
|
+
subclass.extend(DynamicActiveResource::CommonClassMethods)
|
204
|
+
subclass.extend(DynamicActiveResource::Associations)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# shorter name
|
210
|
+
DynARBase = DynamicActiveResource::Base
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module DynamicActiveResource
|
2
|
+
module CommonClassMethods
|
3
|
+
attr_reader :site, :user, :password
|
4
|
+
|
5
|
+
# creates an object of the class in which this module is extended
|
6
|
+
def new(args = {})
|
7
|
+
# @resource_class = create_resource_class() # should this be commented
|
8
|
+
@resource_class.new(args)
|
9
|
+
end
|
10
|
+
|
11
|
+
# sets the site for the class in which this module is extended
|
12
|
+
def site=(site)
|
13
|
+
if site != self.site
|
14
|
+
@site = site
|
15
|
+
uri = URI.parse(site)
|
16
|
+
@user = URI.decode(uri.user) if(uri.user)
|
17
|
+
@password = URI.decode(uri.password) if(uri.password)
|
18
|
+
@resource_class = self.send(:create_resource_class)
|
19
|
+
end
|
20
|
+
@site
|
21
|
+
end
|
22
|
+
|
23
|
+
# sets the user for the class in which this module is extended
|
24
|
+
def user=(user)
|
25
|
+
if user != self.user
|
26
|
+
@user = user
|
27
|
+
@resource_class = self.send(:create_resource_class) if(site)
|
28
|
+
end
|
29
|
+
@user
|
30
|
+
end
|
31
|
+
|
32
|
+
# sets the password for the class in which this module is extended
|
33
|
+
def password=(password)
|
34
|
+
if password != self.password
|
35
|
+
@password = password
|
36
|
+
@resource_class = self.send(:create_resource_class) if(site)
|
37
|
+
end
|
38
|
+
@password
|
39
|
+
end
|
40
|
+
|
41
|
+
# sets the collection name for the class in which this module is extended
|
42
|
+
def collection_name=(collection_name)
|
43
|
+
if collection_name != self.collection_name
|
44
|
+
@collection_name = collection_name
|
45
|
+
end
|
46
|
+
@collection_name
|
47
|
+
end
|
48
|
+
|
49
|
+
# sets the elment name for the class in which this module is extended
|
50
|
+
def element_name=(element_name)
|
51
|
+
if element_name != self.element_name
|
52
|
+
@element_name = element_name
|
53
|
+
end
|
54
|
+
@element_name
|
55
|
+
end
|
56
|
+
|
57
|
+
# collection name for the class in which this module is extended
|
58
|
+
def collection_name
|
59
|
+
@collection_name || class_name.underscore.pluralize
|
60
|
+
end
|
61
|
+
|
62
|
+
# element name for the class in which this module is extended
|
63
|
+
def element_name
|
64
|
+
@element_name || class_name.underscore
|
65
|
+
end
|
66
|
+
|
67
|
+
# routes to active resource find
|
68
|
+
def find(*args)
|
69
|
+
return @resource_class.find_without_pagination(*args) if(@resource_class.respond_to?(:find_without_pagination))
|
70
|
+
scope = args.slice!(0)
|
71
|
+
options = args.slice!(0) || {}
|
72
|
+
obj = @resource_class.find(scope, options)
|
73
|
+
obj
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
# creates an active resource class dynamically. All the attributes are set automatically. Avoid calling
|
78
|
+
# this method directly
|
79
|
+
def create_resource_class
|
80
|
+
# raise exceptions if any of site is not set
|
81
|
+
raise "Please set the site for #{self} class before using create_resource_class()." unless(self.site)
|
82
|
+
|
83
|
+
created_class = Class.new(ActiveResource::Base)
|
84
|
+
|
85
|
+
# set the resource options
|
86
|
+
created_class.site = self.site
|
87
|
+
created_class.user = self.user
|
88
|
+
created_class.password = self.password
|
89
|
+
created_class.collection_name = self.collection_name
|
90
|
+
created_class.element_name = self.element_name
|
91
|
+
|
92
|
+
created_class_name = "#{self}::#{class_name}#{Helpers.fast_token()}"
|
93
|
+
eval "#{created_class_name} = created_class"
|
94
|
+
|
95
|
+
# include the common dynamic methods
|
96
|
+
created_class.send(:include, DynamicActiveResource::CommonDynamicClassInstanceMethods)
|
97
|
+
|
98
|
+
# includes a module called InstanceMethods in the class created dynamically
|
99
|
+
# if it is defined inside the wrapper class
|
100
|
+
inst_meth_mod_name = instance_methods_module_name()
|
101
|
+
created_class.send(:include, self.const_get(inst_meth_mod_name.to_sym)) if inst_meth_mod_name
|
102
|
+
|
103
|
+
# extends the class created dynamically with a module called ClassMethods if
|
104
|
+
# it is defined inside the wrapper class
|
105
|
+
class_meth_mod_name = class_methods_module_name()
|
106
|
+
created_class.extend(self.const_get(class_meth_mod_name)) if class_meth_mod_name
|
107
|
+
# put the associations in the created class also
|
108
|
+
created_class.instance_variable_set(:@associations, @associations)
|
109
|
+
|
110
|
+
created_class
|
111
|
+
end
|
112
|
+
|
113
|
+
def class_name
|
114
|
+
self.name.split('::')[-1]
|
115
|
+
end
|
116
|
+
|
117
|
+
def instance_methods_module_name
|
118
|
+
inst_meth_mod_name = 'DynamicClassInstanceMethods'
|
119
|
+
self.constants.detect { |const| const.split('::')[-1] =~ /#{inst_meth_mod_name}/ }
|
120
|
+
end
|
121
|
+
|
122
|
+
def class_methods_module_name
|
123
|
+
class_meth_mod_name = 'DynamicClassSingletonMethods'
|
124
|
+
self.constants.detect { |const| const.split('::')[-1] =~ /#{class_meth_mod_name}/ }
|
125
|
+
end
|
126
|
+
|
127
|
+
def method_missing(meth_id, *args, &block)
|
128
|
+
@resource_class.send(meth_id, *args, &block)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module DynamicActiveResource
|
2
|
+
module CommonDynamicClassInstanceMethods
|
3
|
+
def method_missing(method_symbol, *arguments) #:nodoc:
|
4
|
+
method_name = method_symbol.to_s
|
5
|
+
# dynamic setters and getters
|
6
|
+
case method_name.last
|
7
|
+
when "="
|
8
|
+
return attributes[method_name.first(-1)] = arguments.first
|
9
|
+
when "?"
|
10
|
+
return attributes[method_name.first(-1)]
|
11
|
+
else
|
12
|
+
# return attributes
|
13
|
+
return attributes[method_name] if(attributes.has_key?(method_name))
|
14
|
+
# return the association if it is a association method
|
15
|
+
return get_association(method_name) if(association_method?(method_name))
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def resource_identifier
|
21
|
+
id()
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def association_method?(method_name)
|
26
|
+
@associations ||= self.class.instance_variable_get(:@associations)
|
27
|
+
return false unless @associations
|
28
|
+
association = @associations.detect { |association| association.method_name.to_s == method_name.to_s }
|
29
|
+
association ? true : false
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_association(method_name)
|
33
|
+
@associations ||= self.class.instance_variable_get(:@associations)
|
34
|
+
association = @associations.detect { |association| association.method_name.to_s == method_name.to_s }
|
35
|
+
association.resources_for(self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DynamicActiveResource
|
2
|
+
module Helpers
|
3
|
+
def Helpers.fast_token
|
4
|
+
values = [
|
5
|
+
rand(0x0010000),
|
6
|
+
rand(0x0010000),
|
7
|
+
rand(0x0010000),
|
8
|
+
rand(0x0010000),
|
9
|
+
rand(0x0010000),
|
10
|
+
rand(0x1000000),
|
11
|
+
rand(0x1000000),
|
12
|
+
]
|
13
|
+
"%04x%04x%04x%04x%04x%06x%06x" % values
|
14
|
+
end
|
15
|
+
|
16
|
+
def Helpers.encode2html(string)
|
17
|
+
html_char_map = {
|
18
|
+
'[' => '%5B', ']' => '%5D',
|
19
|
+
'(' => '%28', ')' => '%29',
|
20
|
+
',' => '%2C', ' ' => '%20',
|
21
|
+
'=' => '%3D', '\'' => '%27',
|
22
|
+
'<' => '%3C', '>' => '%3E',
|
23
|
+
}
|
24
|
+
|
25
|
+
string.strip! if string
|
26
|
+
encoded_string = ''
|
27
|
+
string.each_char do |char|
|
28
|
+
encoded_string << (html_char_map[char] || char)
|
29
|
+
end
|
30
|
+
encoded_string
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arusarka-dynamic-active-resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- asur
|
@@ -31,6 +31,16 @@ extensions: []
|
|
31
31
|
extra_rdoc_files:
|
32
32
|
- README
|
33
33
|
files:
|
34
|
+
- lib/dynamic_active_resource/associations/base.rb
|
35
|
+
- lib/dynamic_active_resource/associations/belongs_to.rb
|
36
|
+
- lib/dynamic_active_resource/associations/has_many.rb
|
37
|
+
- lib/dynamic_active_resource/associations.rb
|
38
|
+
- lib/dynamic_active_resource/base.rb
|
39
|
+
- lib/dynamic_active_resource/common_class_methods.rb
|
40
|
+
- lib/dynamic_active_resource/common_dynamic_class_instance_methods.rb
|
41
|
+
- lib/dynamic_active_resource/helpers.rb
|
42
|
+
- lib/dynamic_active_resource/version.rb
|
43
|
+
- lib/dynamic_active_resource.rb
|
34
44
|
- README
|
35
45
|
- History.txt
|
36
46
|
- init.rb
|