acts_as_git 0.1.0

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