acts_as_git 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc3679a8508f062ffe650d55db72d791a36c0127
4
+ data.tar.gz: 09facb40c19acafa08e3a37b0ae12000f9850232
5
+ SHA512:
6
+ metadata.gz: ef96fa5c6ec73f818a3bec7e89d6ff58871609b4e2e06e21ed4f1bdb363403d233e1e9f5ad4a04fddea793a4eb5379746ef4030d784e2d886c0edfbd14b86399
7
+ data.tar.gz: 48869fd42be00dddfdd0f4c5e325e1c2c1487a4b6be12a5c443ba29953bb3d9ed17e2df1c9a9c1bd29a0a8be03c4f105b424b3f3fe7afd227ed55c30128e6191
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ Gemfile.lock
2
+ .bundle
3
+ .yardoc
4
+ *.rbc
5
+ .rbx/
6
+ doc/
7
+ .DS_Store
8
+ tags
9
+ pkg/*
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ - 2.1
5
+ - rbx-2
6
+ - jruby-19mode
7
+ gemfile:
8
+ - Gemfile
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ ## 0.0.2 (2014/05/28)
2
+
3
+ Enhancements:
4
+
5
+ * Create the directory if not exist on #save
6
+ * #save and #destory methods are not required in prior
7
+
8
+ ## 0.0.1
9
+
10
+ First version
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+ gem 'coveralls', :require => false
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Naotoshi Seo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ ## Examples
2
+
3
+ ActiveRecord is not required, but let me write an example for it.
4
+
5
+ ```ruby
6
+ ActsAsGit.configure do |config|
7
+ config.email = 'test@test.com'
8
+ config.username = 'testuser'
9
+ end
10
+
11
+ class Post < ActiveRecord::Base
12
+ include ActsAsGit
13
+ def self.repodir
14
+ "posts"
15
+ end
16
+
17
+ def filename
18
+ "#{self.id}_body.txt"
19
+ end
20
+ acts_as_git :body => self.instance_method(:filename)
21
+ end
22
+
23
+ # store
24
+ post = Post.new # create the directory `self.repodir` if not exist, and init repo.
25
+ post.body = 'content'
26
+ post.save # save the content into the file of `#filename`
27
+ post.get_commit
28
+ => COMMIT_HASH_HOGE
29
+
30
+ # load
31
+ post = Post.first
32
+ puts post.body
33
+ => 'content'
34
+
35
+ # history
36
+ post.body = 'content2'
37
+ post.is_changed?
38
+ => true
39
+ post.save
40
+ post.is_changed?
41
+ => false
42
+ post.get_commit
43
+ => COMMIT_HASH_FUGA
44
+ puts post.body
45
+ => 'content2'
46
+ post.checkout(COMMIT_HASH_HOGE)
47
+ puts post.body
48
+ => 'content'
49
+ ```
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # coding: utf-8
2
+ require 'bundler/gem_tasks'
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.rspec_opts = ["-c", "-f progress"] # '--format specdoc'
7
+ t.pattern = 'spec/**/*_spec.rb'
8
+ end
9
+ task :test => :spec
10
+ task :default => :spec
11
+
12
+ desc 'Open an irb session preloaded with the gem library'
13
+ task :console do
14
+ sh 'irb -rubygems -I lib -r acts_as_git'
15
+ end
16
+ task :c => :console
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env gem build
2
+ # encoding: utf-8
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "acts_as_git"
6
+ s.authors = ["Satoshi Amemiya", "Naotoshi Seo"]
7
+ s.email = ["rail.sky@gmail.com", "sonots@gmail.com"]
8
+ s.homepage = "https://github.com/rail44/acts_as_git"
9
+ s.summary = "Make your field act as a git repo"
10
+ s.description = "Make your field act as a git repo. Save the content to a file, and load the content from a file."
11
+ s.version = '0.1.0'
12
+ s.date = Time.now.strftime("%Y-%m-%d")
13
+
14
+ s.extra_rdoc_files = Dir["*.rdoc"]
15
+ s.files = `git ls-files`.split($\)
16
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+ s.rdoc_options = ["--charset=UTF-8"]
20
+
21
+ s.add_runtime_dependency 'rugged'
22
+
23
+ s.add_development_dependency 'rspec'
24
+ s.add_development_dependency 'rspec-its'
25
+ s.add_development_dependency 'rake'
26
+ s.add_development_dependency 'pry'
27
+ s.add_development_dependency 'pry-nav'
28
+ end
@@ -0,0 +1,164 @@
1
+ require 'fileutils'
2
+ require 'rugged'
3
+
4
+ module ActsAsGit
5
+ def self.included(klass)
6
+ klass.extend(ClassMethods)
7
+ end
8
+
9
+ def self.configure
10
+ ClassMethods.module_eval do
11
+ yield self
12
+ end
13
+ end
14
+
15
+ # ToDo: rename if filename is changed
16
+ module ClassMethods
17
+ def self.email=(email)
18
+ @@email = email
19
+ end
20
+
21
+ def self.username=(username)
22
+ @@username = username
23
+ end
24
+
25
+ def get_option(index)
26
+ option = {}
27
+ option[:author] = { :email => @@email, :name => @@username, :time => Time.now }
28
+ option[:committer] = { :email => @@email, :name => @@username, :time => Time.now }
29
+ option[:parents] = @@repo.empty? ? [] : [ @@repo.head.target ].compact
30
+ option[:tree] = index.write_tree(@@repo)
31
+ option[:update_ref] = 'HEAD'
32
+ option
33
+ end
34
+
35
+ # acts_as_git :field => self.instance_method(:filename)
36
+ def acts_as_git(params = {})
37
+ self.class_eval do
38
+ unless method_defined?(:save_with_file)
39
+ def self.path(filename)
40
+ File.join(repodir, filename)
41
+ end
42
+
43
+ def commit
44
+ if @commit
45
+ @commit
46
+ else
47
+ (@@repo.empty?)? nil: @@repo.head.target
48
+ end
49
+ end
50
+
51
+ def is_changed?
52
+ (@is_changed)? true: false
53
+ end
54
+
55
+ def get_commit
56
+ (commit)? commit.oid: nil
57
+ end
58
+
59
+ define_method :checkout do |commit|
60
+ @commit = (commit)? @@repo.lookup(commit): nil
61
+ @is_changed = false
62
+ params.each do |field, filename_instance_method|
63
+ field = nil
64
+ end
65
+ self
66
+ end
67
+
68
+ repodir = self.repodir
69
+ FileUtils.mkdir_p(repodir)
70
+ begin
71
+ @@repo = Rugged::Repository.new(repodir)
72
+ rescue
73
+ Rugged::Repository.init_at(repodir)
74
+ @@repo = Rugged::Repository.new(repodir)
75
+ end
76
+
77
+ define_method(:save_with_file) do |*args|
78
+ params.each do |field, filename_instance_method|
79
+ field_name = :"@#{field}"
80
+ repodir = self.class.repodir
81
+ filename = filename_instance_method.bind(self).call
82
+ content = instance_variable_get(field_name)
83
+ if repodir and filename and content
84
+ oid = @@repo.write(content, :blob)
85
+ index = @@repo.index
86
+ path = self.class.path(filename)
87
+ action = File.exists?(path)? 'Update': 'Create'
88
+ FileUtils.mkdir_p(File.dirname(path))
89
+ File.open(path, 'w') do |f|
90
+ f.write(content)
91
+ end
92
+ index.add(path: filename, oid: oid, mode: 0100644)
93
+ option = self.class.get_option(index)
94
+ option[:message] = "#{action} #{filename} for field #{field_name} of #{self.class.name}"
95
+ Rugged::Commit.create(@@repo, option)
96
+ @commit = @@repo.head.target
97
+ @is_changed = false
98
+ index.read_tree(@commit.tree)
99
+ index.write
100
+ instance_variable_set(field_name, nil)
101
+ end
102
+ end
103
+ save_without_file(*args)
104
+ end
105
+
106
+ define_method(:save) {|*args| } unless method_defined?(:save)
107
+ alias_method :save_without_file, :save
108
+ alias_method :save, :save_with_file
109
+
110
+ params.each do |field, filename_instance_method|
111
+ field_name = :"@#{field}"
112
+ define_method("#{field}=") do |content|
113
+ instance_variable_set(field_name, content)
114
+ @is_changed = true
115
+ end
116
+ end
117
+
118
+ params.each do |field, filename_instance_method|
119
+ field_name = :"@#{field}"
120
+ define_method(field) do |offset = nil, length = nil|
121
+ if @is_changed
122
+ return instance_variable_get(field_name)
123
+ end
124
+ filename = filename_instance_method.bind(self).call
125
+ return nil unless repodir
126
+ return nil unless filename
127
+ return nil if @@repo.empty?
128
+ return nil unless fileob = commit.tree[filename]
129
+ oid = fileob[:oid]
130
+ file = StringIO.new(@@repo.lookup(oid).content)
131
+ file.seek(offset) if offset
132
+ file.read(length)
133
+ end
134
+ end
135
+
136
+ define_method(:destroy_with_file) do
137
+ params.each do |field, filename_instance_method|
138
+ field_name = :"@#{field}"
139
+ filename = filename_instance_method.bind(self).call
140
+ index = @@repo.index
141
+ path = self.class.path(filename)
142
+ File.unlink(path) if File.exists?(path)
143
+ begin
144
+ index.remove(filename)
145
+ option = self.class.get_option(index)
146
+ option[:message] = "Remove #{filename} for field #{field_name} of #{self.class.name}"
147
+ Rugged::Commit.create(@@repo, option)
148
+ @commit = @@repo.head.target
149
+ @is_changed = false
150
+ index.read_tree(@commit.tree)
151
+ index.write
152
+ rescue Rugged::IndexError => e
153
+ end
154
+ end
155
+ destroy_without_file
156
+ end
157
+ define_method(:destroy) {} unless method_defined?(:destroy)
158
+ alias_method :destroy_without_file, :destroy
159
+ alias_method :destroy, :destroy_with_file
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,80 @@
1
+ require_relative 'spec_helper'
2
+ require_relative 'model'
3
+
4
+ describe ActsAsGit do
5
+ let(:subject) { TestPost.new }
6
+ after do
7
+ File.unlink(TestPost.path subject.filename) if File.exist?(TestPost.path subject.filename)
8
+ end
9
+
10
+ after(:context) do
11
+ FileUtils.rm_rf(File.join(TestPost.repodir, '.git')) if Dir.exist?(File.join(TestPost.repodir, '.git'))
12
+ end
13
+
14
+ context '#body=' do
15
+ it { expect { subject.body = 'aaaa' }.not_to raise_error }
16
+ end
17
+
18
+ context '#body' do
19
+ context 'get from instance variable' do
20
+ before { subject.body = 'aaaa' }
21
+ its(:body) { should == 'aaaa' }
22
+ end
23
+
24
+ context 'get from file' do
25
+ before { subject.body = 'aaaa' }
26
+ before { subject.save }
27
+ its(:body) { should == 'aaaa' }
28
+ end
29
+
30
+ context 'seek' do
31
+ before { subject.body = 'abcd' }
32
+ before { subject.save }
33
+ it { expect(subject.body(1, 2)).to be == 'bc' }
34
+ end
35
+
36
+ context 'get from commit in the past' do
37
+ before do
38
+ subject.body = 'aaaa'
39
+ subject.save
40
+ @commit = subject.get_commit
41
+ subject.body = 'bbbb'
42
+ subject.save
43
+ end
44
+ it { expect(subject.body).to be == 'bbbb' }
45
+ it do
46
+ subject.checkout(@commit)
47
+ expect(subject.body).to be == 'aaaa'
48
+ end
49
+ end
50
+ end
51
+
52
+ context '#save_with_file' do
53
+ context 'save if body exists' do
54
+ before { subject.body = 'aaaa' }
55
+ before { subject.save }
56
+ it { expect(File.read(TestPost.path(subject.filename))).to eql('aaaa') }
57
+ end
58
+
59
+ context 'does not save if body does not exist' do
60
+ before { subject.body = nil }
61
+ before { subject.save }
62
+ it { expect(File.exist?(TestPost.path(subject.filename))).to be_falsey }
63
+ end
64
+ end
65
+
66
+ context '#destroy_with_file' do
67
+ context 'delete if file exists' do
68
+ before { subject.body = 'aaaa' }
69
+ before { subject.save }
70
+ before { subject.destroy }
71
+ it { expect(File.exist?(TestPost.path(subject.filename))).to be_falsey }
72
+ end
73
+
74
+ context 'fine even if file does not exist' do
75
+ before { subject.destroy }
76
+ it { expect(File.exist?(TestPost.path(subject.filename))).to be_falsey }
77
+ end
78
+ end
79
+ end
80
+
data/spec/model.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'acts_as_git'
2
+
3
+ ActsAsGit.configure do |config|
4
+ config.email = 'test@test.com'
5
+ config.username = 'testuser'
6
+ end
7
+
8
+ class TestPost
9
+ include ActsAsGit
10
+ def self.repodir
11
+ @@repodir = Dir.tmpdir
12
+ end
13
+
14
+ def filename
15
+ @filename = 'test_acts_as_git'
16
+ end
17
+ acts_as_git :body => self.instance_method(:filename)
18
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'rspec/its'
4
+ require 'pry'
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
6
+
7
+ if ENV['TRAVIS']
8
+ require 'coveralls'
9
+ Coveralls.wear!
10
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_git
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Satoshi Amemiya
8
+ - Naotoshi Seo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-06-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rugged
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec-its
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry-nav
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description: Make your field act as a git repo. Save the content to a file, and load
99
+ the content from a file.
100
+ email:
101
+ - rail.sky@gmail.com
102
+ - sonots@gmail.com
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - .gitignore
108
+ - .travis.yml
109
+ - CHANGELOG.md
110
+ - Gemfile
111
+ - LICENSE
112
+ - README.md
113
+ - Rakefile
114
+ - acts_as_git.gemspec
115
+ - lib/acts_as_git.rb
116
+ - spec/acts_as_git_spec.rb
117
+ - spec/model.rb
118
+ - spec/spec_helper.rb
119
+ homepage: https://github.com/rail44/acts_as_git
120
+ licenses: []
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options:
124
+ - --charset=UTF-8
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.0.14
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Make your field act as a git repo
143
+ test_files:
144
+ - spec/acts_as_git_spec.rb
145
+ - spec/model.rb
146
+ - spec/spec_helper.rb