stuff_arc 0.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/Gemfile +5 -0
- data/LICENSE +1 -0
- data/README.md +77 -0
- data/Rakefile +42 -0
- data/lib/stuff_arc.rb +89 -0
- data/tests/stuff_arc_test.rb +86 -0
- metadata +63 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
include LGPL 3
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# stuff_arc - supports Rails portable data dump and restore
|
2
|
+
|
3
|
+
## Version 0.0.2
|
4
|
+
|
5
|
+
stuff_arc adds class level archiving and unarchiving of an ActiveRecord object
|
6
|
+
a Rails app.
|
7
|
+
|
8
|
+
Archives are JSON data, one line per model instance with the 'id' value omitted so that
|
9
|
+
the data can be restored w/o worrying about primary key clashes.
|
10
|
+
|
11
|
+
Restoration is performed by instantiating the model and then calling save!. **save!** exceptions
|
12
|
+
are trapped and generate simple error messages, thus Rails validations can be used to avoid
|
13
|
+
data duplication and data clobbering.
|
14
|
+
|
15
|
+
These methods are designed to be used in a Rails Console, not programatically.
|
16
|
+
|
17
|
+
## Install
|
18
|
+
|
19
|
+
gem install stuff_arc
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Include into models in which you want to create archives.
|
24
|
+
|
25
|
+
app/models/foo.rb:
|
26
|
+
|
27
|
+
require 'stuff_arc'
|
28
|
+
|
29
|
+
class Foo < ActiveRecord::Base
|
30
|
+
include StuffArc
|
31
|
+
|
32
|
+
. . .
|
33
|
+
end
|
34
|
+
|
35
|
+
This will add two class methods to Foo:
|
36
|
+
|
37
|
+
* Foo.archive(options = {}) - which will create the file 'foos.json' containing JSON serializations
|
38
|
+
of every record retrieved by Foo.all with the 'id' entry is excluded.
|
39
|
+
* Foo.unarchive(options = {}) - which reads the file 'foos.json', decodes each record and attempts
|
40
|
+
to save! them to the database.
|
41
|
+
|
42
|
+
The options are:
|
43
|
+
|
44
|
+
* :fname - name of archive file. Defaults to the _underscored_, _pluralized_ version of the
|
45
|
+
class name with the '.json' suffix.
|
46
|
+
* :lib\_dir - path to directory archives are placed/looked for in. **NOTE:** :lib\_dir is ignored if
|
47
|
+
:fname is an absolute path. Defaults to:
|
48
|
+
|
49
|
+
<app root>/lib/stuff\_arc - if Rails.public\_path is defined
|
50
|
+
|
51
|
+
'.' - if Rails.public\_path is not defined
|
52
|
+
|
53
|
+
|
54
|
+
This creates a portable dump and restore facility for each model in which StuffArc is
|
55
|
+
included.
|
56
|
+
|
57
|
+
## Creating an Archive
|
58
|
+
|
59
|
+
Fire up the rails console [rails c] and . . .
|
60
|
+
|
61
|
+
Create an archive in the default directory with default name:
|
62
|
+
|
63
|
+
Foo.archive
|
64
|
+
|
65
|
+
Create an archive in the default directory with a different name
|
66
|
+
|
67
|
+
Foo.archive :fname => 'foobar'
|
68
|
+
|
69
|
+
Create an archive in a specified directory with the default name
|
70
|
+
|
71
|
+
Foo.archive :lib_dir => '/tmp'
|
72
|
+
|
73
|
+
## Restoring an Archive
|
74
|
+
|
75
|
+
Fire up the rails console [rails c] and . . .
|
76
|
+
|
77
|
+
repeat one of the commands above using **Foo.unarchive** instead of *Foo.archive*
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
gem_name = 'stuff_arc'
|
4
|
+
|
5
|
+
# snarf gemspec and set version
|
6
|
+
gem_spec = eval File.new("#{gem_name}.gemspec").read
|
7
|
+
gem_version = gem_spec.version.to_s
|
8
|
+
|
9
|
+
gem_zip = "#{gem_name}_#{gem_version}.zip"
|
10
|
+
gem_tgz = "#{gem_name}_#{gem_version}.tgz"
|
11
|
+
|
12
|
+
task :default => :test
|
13
|
+
|
14
|
+
desc "Run unit tests"
|
15
|
+
task :test do
|
16
|
+
system 'ruby tests/*'
|
17
|
+
# require "./test/#{gem_name}_base_test"
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "run rdoc to create doc"
|
21
|
+
task :doc do
|
22
|
+
system 'rdoc'
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "build gem"
|
26
|
+
task :gem do
|
27
|
+
system "gem build #{gem_name}.gemspec"
|
28
|
+
if 'mike.local' == IO.popen('hostname').read.chomp
|
29
|
+
system "cp #{gem_name}-#{gem_version}.gem ~/Rails/GemCache/gems/"
|
30
|
+
system "(cd ~/Rails/GemCache ; gem generate_index -d . )"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "push to github"
|
35
|
+
task :git_push do
|
36
|
+
system 'git push'
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "push to rubygems"
|
40
|
+
task :gem_push => :gem do
|
41
|
+
system "gem push #{gem_name}-#{gem_version}.gem"
|
42
|
+
end
|
data/lib/stuff_arc.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# StuffArc - supports portable Rails databases dump and restore
|
2
|
+
#
|
3
|
+
# defines two class level methods for archiving and unarchiving ActiveRecord::Base
|
4
|
+
# objects.
|
5
|
+
#
|
6
|
+
# archive - creates an archive named <class.underscore>.json containing JSON representations
|
7
|
+
# of each instance of the model
|
8
|
+
#
|
9
|
+
# unarchive - which reads a file created by **archive** (named <class.underscore>.json) and
|
10
|
+
# saves each record in the datbase.
|
11
|
+
#
|
12
|
+
# Both methods are designed to be run from a Rails Console - not programatically.
|
13
|
+
|
14
|
+
require 'rails'
|
15
|
+
# require 'pry'
|
16
|
+
# require 'active_support'
|
17
|
+
# require 'active_support/inflector'
|
18
|
+
# require 'active_support/json'
|
19
|
+
|
20
|
+
module StuffArc
|
21
|
+
VERSION = "0.0.3"
|
22
|
+
|
23
|
+
def self.included(mod)
|
24
|
+
mod_lowercase = mod.to_s.underscore.pluralize
|
25
|
+
tmp =<<-EOF
|
26
|
+
def self.archive options = {}
|
27
|
+
unless (lib_dir = options.delete(:lib_dir))
|
28
|
+
if Rails.public_path
|
29
|
+
lib_dir = File.join( File.dirname(::Rails.public_path), 'lib', 'stuff_arc' )
|
30
|
+
Dir.mkdir(lib_dir) unless File.exists? lib_dir
|
31
|
+
else
|
32
|
+
lib_dir = '.'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
fname = options.delete(:fname) || '#{mod_lowercase}.json'
|
36
|
+
fname = File.join(lib_dir, fname) unless fname[0] == File::SEPARATOR
|
37
|
+
|
38
|
+
if File.exists? fname
|
39
|
+
back_name = fname + '~'
|
40
|
+
File.unlink back_name if File.exists? back_name
|
41
|
+
File.rename fname, back_name
|
42
|
+
end
|
43
|
+
f = File.open(fname, 'w')
|
44
|
+
list = self.all
|
45
|
+
list.each do |#{mod_lowercase}|
|
46
|
+
json_str = ActiveSupport::JSON.encode #{mod_lowercase}, :include_root_in_json => false, :except => :id
|
47
|
+
f.write json_str + "\n"
|
48
|
+
end
|
49
|
+
f.close
|
50
|
+
list.length
|
51
|
+
end
|
52
|
+
EOF
|
53
|
+
|
54
|
+
mod.instance_eval tmp, __FILE__, __LINE__
|
55
|
+
|
56
|
+
tmp =<<-EOF
|
57
|
+
def self.unarchive options = {}
|
58
|
+
unless (lib_dir = options.delete(:lib_dir))
|
59
|
+
if Rails.public_path
|
60
|
+
lib_dir = File.join( File.dirname(::Rails.public_path), 'lib', 'stuff_arc' )
|
61
|
+
Dir.mkdir(lib_dir) unless File.exists? lib_dir
|
62
|
+
else
|
63
|
+
lib_dir = '.'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
fname = options.delete(:fname) || '#{mod_lowercase}.json'
|
67
|
+
fname = File.join(lib_dir, fname) unless fname[0] == File::SEPARATOR
|
68
|
+
|
69
|
+
return nil unless File.exists? fname
|
70
|
+
|
71
|
+
f = File.new fname
|
72
|
+
|
73
|
+
f.lines do |line|
|
74
|
+
#{mod_lowercase} = self.new Hash[ActiveSupport::JSON.decode(line).map { |k,v| [k.to_sym, v] }]
|
75
|
+
begin
|
76
|
+
#{mod_lowercase}.save!
|
77
|
+
rescue Exception => e
|
78
|
+
puts "exception unarchiving #{mod_lowercase}: \#{e}\n"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
f.close
|
83
|
+
end
|
84
|
+
EOF
|
85
|
+
|
86
|
+
mod.instance_eval tmp, __FILE__, __LINE__
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
$LOAD_PATH << File.expand_path("../../lib", __FILE__)
|
2
|
+
require 'test/unit'
|
3
|
+
require 'stuff_arc'
|
4
|
+
# require 'active_model'
|
5
|
+
|
6
|
+
class StuffArcHelper
|
7
|
+
include StuffArc
|
8
|
+
|
9
|
+
class <<self
|
10
|
+
attr_accessor :db
|
11
|
+
|
12
|
+
def init_db
|
13
|
+
self.db = []
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_accessor :foo, :bar
|
18
|
+
|
19
|
+
def initialize args = nil
|
20
|
+
unless args.nil?
|
21
|
+
self.foo = args[:foo] if args[:foo]
|
22
|
+
self.bar = args[:bar] if args[:bar]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def ==(other)
|
27
|
+
self.foo == other.foo && self.bar == other.bar
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.all
|
31
|
+
[self.new({foo: 'foo', bar: 'bar'}), self.new({foo: 'foo2', bar: 'bar2'})]
|
32
|
+
end
|
33
|
+
|
34
|
+
def save!
|
35
|
+
StuffArcHelper.db << self
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class StuffArcTest < Test::Unit::TestCase
|
40
|
+
# def setup
|
41
|
+
# puts "StuffArcHelper.public_methods: #{StuffArcHelper.public_methods.grep /arc/}"
|
42
|
+
# end
|
43
|
+
|
44
|
+
def teardown
|
45
|
+
fname = StuffArcHelper.to_s.underscore.pluralize + '.json'
|
46
|
+
[fname, fname + '~'].each do |fn|
|
47
|
+
File.unlink(fn) if File.exists? fn
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_methods_exist
|
52
|
+
assert StuffArcHelper.respond_to?(:archive), "StuffArcHelper has class method :archive"
|
53
|
+
assert StuffArcHelper.respond_to?(:unarchive), "StuffArcHelper has class method :unarchive"
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_creates_archive
|
57
|
+
StuffArcHelper.archive
|
58
|
+
fname = StuffArcHelper.to_s.underscore
|
59
|
+
assert_equal 'stuff_arc_helper', fname, "underscore should transform class name correctly"
|
60
|
+
assert File.exists?('stuff_arc_helpers.json'), "archive creates a file"
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_reads_archive
|
64
|
+
StuffArcHelper.archive
|
65
|
+
StuffArcHelper.init_db
|
66
|
+
assert_equal [], StuffArcHelper.db, "StuffArcHelper.init_db should empty db"
|
67
|
+
StuffArcHelper.unarchive
|
68
|
+
assert_equal StuffArcHelper.all, StuffArcHelper.db, "Unarchiving should fill db"
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_full_path_to_archive
|
72
|
+
path = File.join(Dir.pwd, 'path-to-archive')
|
73
|
+
Dir.mkdir(path) unless File.exists? path
|
74
|
+
StuffArcHelper.archive :lib_dir => path
|
75
|
+
assert File.exists?(File.join(path, 'stuff_arc_helpers.json')), "archive should be in #{path}"
|
76
|
+
File.unlink File.join(path, 'stuff_arc_helpers.json') if File.exists? File.join(path, 'stuff_arc_helpers.json')
|
77
|
+
Dir.rmdir path if File.exists? path
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_fname_override
|
81
|
+
fname = 'foo-stuff'
|
82
|
+
StuffArcHelper.archive :fname => fname
|
83
|
+
assert File.exists?(fname), "file #{fname} should exist"
|
84
|
+
File.unlink(fname) if File.exists? fname
|
85
|
+
end
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stuff_arc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mike Howard
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-07 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: &2166654720 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2166654720
|
25
|
+
description: stuff_arc - adds class level archiving/unarchiving to ActiveRecord::Base
|
26
|
+
children
|
27
|
+
email: mike@clove.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/stuff_arc.rb
|
33
|
+
- tests/stuff_arc_test.rb
|
34
|
+
- LICENSE
|
35
|
+
- Rakefile
|
36
|
+
- README.md
|
37
|
+
- Gemfile
|
38
|
+
homepage: http://github.com/mikehoward/stuff_arc
|
39
|
+
licenses: []
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.8.6
|
59
|
+
signing_key:
|
60
|
+
specification_version: 3
|
61
|
+
summary: stuff_arc - adds class level archiving/unarchiving to ActiveRecord::Base
|
62
|
+
children
|
63
|
+
test_files: []
|