inactive_record 1.0.3

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/History.txt ADDED
@@ -0,0 +1,13 @@
1
+ == 1.0.3 2010-01-04
2
+
3
+ * Added a :methods option to #to_xml that acts just as its ActiveRecord counterpart does.
4
+ * Refactored #to_xml to be more concise.
5
+
6
+ == 1.0.2 2009-06-24
7
+
8
+ * Add attr_human_name method.
9
+
10
+
11
+ == 1.0.0 2009-04-03
12
+
13
+ * Initial release
data/README.rdoc ADDED
@@ -0,0 +1,82 @@
1
+ = inactive_record
2
+
3
+ http://github.com/midas/inactive_record/tree/master
4
+
5
+
6
+ == DESCRIPTION:
7
+
8
+ InactiveRecord gives you many of the features you know and love from ActiveRecord without the need for a backing
9
+ database table.
10
+
11
+
12
+ == FEATURES:
13
+
14
+ * An initialize method that accepts an attribute hash, including the Rails Date/Time select methods (ie. start_date(1i), etc...)
15
+ * A to_xml method that accepts the same options as its respective ActiveRecord method
16
+ * All validations work when you call valid?, excluding validates_uniqueness_of
17
+ * Supports errors_for method (when validations fail, just render the new or edit form as you mormaly would)
18
+ * Works with Rails 2.3
19
+
20
+
21
+ ==PROBLEMS:
22
+
23
+
24
+ == INSTALL:
25
+
26
+ sudo gem install midas-inactive_record
27
+
28
+
29
+ == USE:
30
+
31
+ Add gem requirement to your environment.rb file:
32
+
33
+ config.gem 'midas-inactive_record', :version => '1.0.0', :lib => 'inactive_record', :source => 'http://gems.github.com'
34
+
35
+ Create a model class:
36
+
37
+ class Thing < InactiveRecord::Base
38
+ attr_accessor :name, :begin_date, :end_date
39
+ validates_presence_of :name, :begin_date, :end_date
40
+ end
41
+
42
+ In things_controller.rb:
43
+
44
+ @thing = Thing.new( params[:thing] )
45
+
46
+ unless @thing.valid?
47
+ render :new
48
+ return
49
+ end
50
+
51
+ Now you can use errors_for, etc in your forms.
52
+
53
+
54
+ == REQUIREMENTS:
55
+
56
+ * ActiveRecord >= 2.2.0
57
+
58
+
59
+ == LICENSE:
60
+
61
+ (The MIT License)
62
+
63
+ Copyright (c) 2009 C. Jason Harrelson (midas)
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining
66
+ a copy of this software and associated documentation files (the
67
+ 'Software'), to deal in the Software without restriction, including
68
+ without limitation the rights to use, copy, modify, merge, publish,
69
+ distribute, sublicense, and/or sell copies of the Software, and to
70
+ permit persons to whom the Software is furnished to do so, subject to
71
+ the following conditions:
72
+
73
+ The above copyright notice and this permission notice shall be
74
+ included in all copies or substantial portions of the Software.
75
+
76
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
77
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
78
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
79
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
80
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
81
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
82
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "inactive_record"
8
+ gem.summary = %Q{InactiveRecord gives you many of the features you know and love from ActiveRecord without the need for a backing database table.}
9
+ gem.description = %Q{InactiveRecord gives you many of the features you know and love from ActiveRecord without the need for a backing database table.}
10
+ gem.email = "jason@lookforwardenterprises.com"
11
+ gem.homepage = "http://github.com/midas/inactive_record"
12
+ gem.authors = ["C. Jason Harrelson (midas)"]
13
+ gem.add_dependency "activerecord", ">= 2.2"
14
+ gem.add_development_dependency "rspec", ">= 1.2.9"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+ task :spec => :check_dependencies
35
+
36
+ task :default => :spec
37
+
38
+ require 'rake/rdoctask'
39
+ Rake::RDocTask.new do |rdoc|
40
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = "inactive_record #{version}"
44
+ rdoc.rdoc_files.include('README*')
45
+ rdoc.rdoc_files.include('lib/**/*.rb')
46
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.3
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{inactive_record}
8
+ s.version = "1.0.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["C. Jason Harrelson (midas)"]
12
+ s.date = %q{2010-01-04}
13
+ s.description = %q{InactiveRecord gives you many of the features you know and love from ActiveRecord without the need for a backing database table.}
14
+ s.email = %q{jason@lookforwardenterprises.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "History.txt",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "inactive_record.gemspec",
24
+ "lib/inactive_record.rb",
25
+ "lib/inactive_record/base.rb",
26
+ "script/console",
27
+ "script/destroy",
28
+ "script/generate",
29
+ "spec/inactive_record/base_spec.rb",
30
+ "spec/inactive_record_spec.rb",
31
+ "spec/spec.opts",
32
+ "spec/spec_helper.rb",
33
+ "tasks/rspec.rake"
34
+ ]
35
+ s.homepage = %q{http://github.com/midas/inactive_record}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.5}
39
+ s.summary = %q{InactiveRecord gives you many of the features you know and love from ActiveRecord without the need for a backing database table.}
40
+ s.test_files = [
41
+ "spec/inactive_record/base_spec.rb",
42
+ "spec/inactive_record_spec.rb",
43
+ "spec/spec_helper.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<activerecord>, [">= 2.2"])
52
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
53
+ else
54
+ s.add_dependency(%q<activerecord>, [">= 2.2"])
55
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<activerecord>, [">= 2.2"])
59
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
60
+ end
61
+ end
62
+
@@ -0,0 +1,191 @@
1
+ require 'active_record'
2
+ require 'active_record/base'
3
+
4
+ module InactiveRecord
5
+ class Base
6
+
7
+ def initialize( attributes={} )
8
+ unless attributes.nil?
9
+ # Fix any dates/times from rails date_select
10
+ keys = attributes.keys
11
+ date_keys = keys.grep(/(1i)/)
12
+ time_keys = keys.grep(/(4i)/)
13
+ date_keys.each do |date_key|
14
+ key = date_key.to_s.gsub( /\(1i\)/, '' )
15
+ num = keys.grep( /#{key.to_s}/ ).size
16
+ if num == 3
17
+ # Date
18
+ attributes[key.to_sym] = Date.civil( attributes.delete( "#{key}(1i)".to_sym ).to_i,
19
+ attributes.delete( "#{key}(2i)".to_sym ).to_i, attributes.delete( "#{key}(3i)".to_sym ).to_i )
20
+ elsif num == 5
21
+ #DateTime
22
+ attributes[key.to_sym] = DateTime.civil( attributes.delete( "#{key}(1i)".to_sym ).to_i,
23
+ attributes.delete( "#{key}(2i)".to_sym ).to_i, attributes.delete( "#{key}(3i)".to_sym ).to_i,
24
+ attributes.delete( "#{key}(4i)".to_sym ).to_i, attributes.delete( "#{key}(5i)".to_sym ).to_i )
25
+ elsif num == 6
26
+ #DateTime
27
+ attributes[key.to_sym] = DateTime.civil( attributes.delete( "#{key}(1i)".to_sym ).to_i,
28
+ attributes.delete( "#{key}(2i)".to_sym ).to_i, attributes.delete( "#{key}(3i)".to_sym ).to_i,
29
+ attributes.delete( "#{key}(4i)".to_sym ).to_i, attributes.delete( "#{key}(5i)".to_sym ).to_i,
30
+ attributes.delete( "#{key}(6i)".to_sym ).to_i )
31
+ end
32
+ end
33
+
34
+ attributes.each do |key, value|
35
+ self.instance_variable_set("@#{key}", value)
36
+ end
37
+ end
38
+ yield self if block_given?
39
+ end
40
+
41
+ def []( key )
42
+ instance_variable_get("@#{key}")
43
+ end
44
+
45
+ def method_missing( method_id, *args )
46
+ if md = /_before_type_cast$/.match(method_id.to_s)
47
+ attr_name = md.pre_match
48
+ return self[attr_name] if self.respond_to?(attr_name)
49
+ end
50
+ super
51
+ end
52
+
53
+ # Instructions on how to build xml for an object.
54
+ #
55
+ # *options*
56
+ # :only - A symbol or array of symbols of instance variable names to include in the xml.
57
+ # :except - A symbol or array of symbols of instance variable names to exclude in the xml.
58
+ # :methods - A symbol or array of symbols of methods to evaluate and include in the xml.
59
+ # :skip_instruct - If true, output the document type, otherwise do not.
60
+ # :skip_types - (not yet) If true, do not output types of variables that are not strings.
61
+ # :include - (not yet) First level associations to include.
62
+ # :dasherize - If true, convert underscored variable names to dasherized variable names.
63
+ #
64
+ def to_xml( options={} )
65
+ options[:indent] ||= 2
66
+ except = options[:except]
67
+ methods = options[:methods]
68
+ only = options[:only]
69
+ throw 'Both the :except and :only options cannot be used simultaneously.' if !except.nil? && !only.nil?
70
+
71
+ only = only.map { |attribute| attribute.to_sym } if only.is_a?( Array )
72
+ only = Array.new << only.to_sym if only.is_a?( String )
73
+ only = Array.new << only if only.is_a?( Symbol )
74
+ except = except.map { |attribute| attribute.to_sym } if except.is_a?( Array )
75
+ except = Array.new << except.to_sym if except.is_a?( String )
76
+ except = Array.new << except if except.is_a?( Symbol )
77
+ methods = methods.map { |attribute| attribute.to_sym } if methods.is_a?( Array )
78
+ methods = Array.new << methods.to_sym if methods.is_a?( String )
79
+ methods = Array.new << methods if methods.is_a?( Symbol )
80
+ dasherize = options[:dasherize]
81
+ dasherize = true unless !dasherize.nil?
82
+
83
+ attrs = self.instance_variables.map { |var| var.to_s.gsub( /@/, '' ).to_sym }
84
+ to_serialize = []
85
+ to_serialize += methods unless methods.nil?
86
+ if only
87
+ to_serialize += (attrs.select { |var| only.include?( var ) })
88
+ elsif except
89
+ to_serialize += (attrs - except)
90
+ else
91
+ to_serialize += attrs unless attrs.nil?
92
+ end
93
+
94
+ xml = options[:builder] ||= Builder::XmlMarkup.new( :indent => options[:indent] )
95
+ xml.instruct! unless options[:skip_instruct]
96
+ el_tag_name = dasherize ? self.class.to_s.underscore.dasherize : self.class.to_s.underscore
97
+ xml.tag!( el_tag_name ) do
98
+ to_serialize.each do |attribute|
99
+ var_name = dasherize ? attribute.to_s.dasherize : attribute
100
+ attr_val = self.send( attribute ) if self.respond_to?( attribute )
101
+ if attr_val.is_a?( Array )
102
+ xml << attr_val.to_xml( :skip_instruct => true )
103
+ else
104
+ if attr_val.nil?
105
+ is_nil = 'true'
106
+ elsif attr_val.is_a?( TrueClass ) || attr_val.is_a?( FalseClass )
107
+ type = 'boolean'
108
+ elsif attr_val.is_a?( Integer ) || attr_val.is_a?( Fixnum )
109
+ type = 'integer'
110
+ elsif attr_val.is_a?( Float )
111
+ type = 'float'
112
+ elsif attr_val.is_a?( DateTime ) || attr_val.is_a?( Date ) || attr_val.is_a?( Time )
113
+ type = 'datetime'
114
+ end
115
+
116
+ if is_nil
117
+ xml.tag!( var_name, attr_val, :nil => is_nil ) #unless attr_val.nil?
118
+ elsif type
119
+ xml.tag!( var_name, attr_val, :type => type ) #unless attr_val.nil?
120
+ else
121
+ xml.tag!( var_name, attr_val ) #unless attr_val.nil?
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ def new_record?
129
+ true
130
+ end
131
+
132
+ def self.self_and_descendents_from_active_record
133
+ [self]
134
+ end
135
+
136
+ def self.self_and_descendants_from_active_record
137
+ [self]
138
+ end
139
+
140
+ def self.human_name( options={} )
141
+ Base.human_attribute_name(@name)
142
+ end
143
+
144
+ # Allows alternate humanized versions of attributes to be set. For example, an attribute such as 'num_employees' would be
145
+ # converted to 'Num employees' normally using <tt>human_attribute_name</tt>. More descriptive text can be set. Example:
146
+ # attr_human_name 'num_employees' => 'Number of employees'
147
+ def self.attr_human_name(attributes) # :nodoc:
148
+ attributes.stringify_keys!
149
+ write_inheritable_hash("attr_human_name", attributes || {})
150
+
151
+ # assign the current class to each column that is being assigned a new human attribute name
152
+ #self.columns.reject{|c| !attributes.has_key?(c.name)}.each{|c| c.parent_record_class = self}
153
+ end
154
+
155
+ def self.human_name_attributes # :nodoc:
156
+ read_inheritable_attribute("attr_human_name")
157
+ end
158
+
159
+ # Transforms attribute key names into a more humane format, such as "First name" instead of "first_name". Example:
160
+ # Person.human_attribute_name("first_name") # => "First name"
161
+ def self.human_attribute_name(attribute_key_name) #:nodoc:
162
+ (read_inheritable_attribute("attr_human_name") || {})[attribute_key_name.to_s] || ""
163
+ end
164
+
165
+ protected
166
+
167
+ def raise_not_implemented_error(*params)
168
+ ValidatingModel.raise_not_implemented_error(*params)
169
+ end
170
+
171
+ alias save raise_not_implemented_error
172
+ alias update_attribute raise_not_implemented_error
173
+ alias save! raise_not_implemented_error
174
+
175
+ public
176
+ include ActiveRecord::Validations
177
+
178
+ class << self
179
+ def raise_not_implemented_error(*params)
180
+ raise NotImplementedError
181
+ end
182
+
183
+ alias validates_uniqueness_of raise_not_implemented_error
184
+ alias create! raise_not_implemented_error
185
+ alias validate_on_create raise_not_implemented_error
186
+ alias validate_on_update raise_not_implemented_error
187
+ alias save_with_validation raise_not_implemented_error
188
+ end
189
+
190
+ end
191
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'inactive_record/base'
5
+
6
+ module InactiveRecord
7
+ VERSION = '1.0.3'
8
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/inactive_record.rb'}"
9
+ puts "Loading inactive_record gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
File without changes
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ # Time to add your specs!
4
+ # http://rspec.info/
5
+ describe "Place your specs here" do
6
+
7
+ it "find this spec in spec directory" do
8
+ violated "Be sure to write your specs"
9
+ end
10
+
11
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'inactive_record'
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inactive_record
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.3
5
+ platform: ruby
6
+ authors:
7
+ - C. Jason Harrelson (midas)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-04 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "2.2"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.9
34
+ version:
35
+ description: InactiveRecord gives you many of the features you know and love from ActiveRecord without the need for a backing database table.
36
+ email: jason@lookforwardenterprises.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.rdoc
43
+ files:
44
+ - History.txt
45
+ - README.rdoc
46
+ - Rakefile
47
+ - VERSION
48
+ - inactive_record.gemspec
49
+ - lib/inactive_record.rb
50
+ - lib/inactive_record/base.rb
51
+ - script/console
52
+ - script/destroy
53
+ - script/generate
54
+ - spec/inactive_record/base_spec.rb
55
+ - spec/inactive_record_spec.rb
56
+ - spec/spec.opts
57
+ - spec/spec_helper.rb
58
+ - tasks/rspec.rake
59
+ has_rdoc: true
60
+ homepage: http://github.com/midas/inactive_record
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --charset=UTF-8
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.3.5
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: InactiveRecord gives you many of the features you know and love from ActiveRecord without the need for a backing database table.
87
+ test_files:
88
+ - spec/inactive_record/base_spec.rb
89
+ - spec/inactive_record_spec.rb
90
+ - spec/spec_helper.rb