activegist 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.travis.yml +9 -0
- data/CHANGELOG +2 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +96 -0
- data/Rakefile +15 -0
- data/activegist.gemspec +29 -0
- data/lib/active_gist.rb +134 -0
- data/lib/active_gist/api.rb +33 -0
- data/lib/active_gist/attributes.rb +107 -0
- data/lib/active_gist/class_methods.rb +42 -0
- data/lib/active_gist/errors/invalid.rb +5 -0
- data/lib/active_gist/files.rb +40 -0
- data/lib/active_gist/version.rb +8 -0
- data/lib/activegist.rb +1 -0
- data/spec/fixtures/all_gists.json +87 -0
- data/spec/fixtures/gist_1.json +78 -0
- data/spec/fixtures/gist_1_star.json +4 -0
- data/spec/fixtures/gist_1_updated.json +71 -0
- data/spec/fixtures/gist_2.json +65 -0
- data/spec/fixtures/gist_2_star.json +4 -0
- data/spec/fixtures/gist_delete_star.json +4 -0
- data/spec/fixtures/gist_destroy.json +4 -0
- data/spec/fixtures/gist_forked.json +33 -0
- data/spec/fixtures/gist_put_star.json +4 -0
- data/spec/fixtures/new_gist.json +63 -0
- data/spec/fixtures/public_gists.json +61 -0
- data/spec/fixtures/starred_gists.json +35 -0
- data/spec/lib/active_gist/files_spec.rb +16 -0
- data/spec/lib/active_gist_spec.rb +308 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/fakeweb.rb +20 -0
- metadata +173 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Colin MacKenzie IV
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
'Software'), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
= ActiveGist! {<img src="https://secure.travis-ci.org/sinisterchipmunk/active-gist.png" />}[http://travis-ci.org/sinisterchipmunk/active-gist]
|
2
|
+
|
3
|
+
I needed a Ruby library to perform basic create, read, update and delete operations on Gists. I looked, I saw basically nothing (except hacky, test-less tools), and I decided to roll my own. Here's the result.
|
4
|
+
|
5
|
+
ActiveGist is so named because it wraps GitHub's Gist API with a class implementing the ActiveModel modules. So, it should be pretty familiar to anyone who's ever used models in Ruby on Rails.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
The obligatory installation steps, in case you haven't yet figured out they're the same as any other gem...
|
10
|
+
|
11
|
+
gem install activegist
|
12
|
+
|
13
|
+
== Usage
|
14
|
+
|
15
|
+
require 'rubygems' # on old rubies
|
16
|
+
require 'activegist'
|
17
|
+
|
18
|
+
# Set up credentials. A required step, as far as I know.
|
19
|
+
ActiveGist::API.username = "gist owner's github username"
|
20
|
+
ActiveGist::API.password = "gist owner's github password"
|
21
|
+
|
22
|
+
# Various examples of creating and saving a new gist
|
23
|
+
gist = ActiveGist.new
|
24
|
+
gist.description = "gist description"
|
25
|
+
gist.files #=> {}
|
26
|
+
gist.files['test.txt'] = { :content => 'file content' }
|
27
|
+
gist.save #=> true or false
|
28
|
+
gist.save! #=> raise an error on validation error
|
29
|
+
|
30
|
+
# gists are private by default. To make them public, pass a :public option.
|
31
|
+
gist = ActiveGist.new :public => true,
|
32
|
+
:description => "optional",
|
33
|
+
:files => { 'test.txt' => { :content => 'file content' } })
|
34
|
+
gist.save
|
35
|
+
|
36
|
+
gist = ActiveGist.create!(:files => { 'test.txt' => { :content => 'file content' } })
|
37
|
+
|
38
|
+
# Check if gist is valid
|
39
|
+
gist = ActiveGist.new
|
40
|
+
gist.valid? #=> false
|
41
|
+
gist.errors.full_messages #=> ["Files can't be blank"]
|
42
|
+
gist.errors[:files] #=> ["can't be blank"]
|
43
|
+
|
44
|
+
# Find an existing gist if you know its ID
|
45
|
+
gist = ActiveGist.find id
|
46
|
+
gist.public? #=> true if the gist is public, false otherwise
|
47
|
+
gist.files
|
48
|
+
#=>
|
49
|
+
# {"test.txt"=>
|
50
|
+
# {"type"=>"text/plain",
|
51
|
+
# "content"=>"file content",
|
52
|
+
# "raw_url"=>"https://gist.github.com/.../test.txt",
|
53
|
+
# "size"=>12,
|
54
|
+
# "filename"=>"test.txt",
|
55
|
+
# "language"=>"Text"
|
56
|
+
# }
|
57
|
+
# }
|
58
|
+
|
59
|
+
# Fork an existing gist. Yes, really.
|
60
|
+
gist = ActiveGist.find id
|
61
|
+
forked_gist = gist.fork
|
62
|
+
|
63
|
+
# Check if gist is already starred, then star it, then unstar it.
|
64
|
+
# (Unlike most methods, these take effect immediately!)
|
65
|
+
gist = ActiveGist.find id
|
66
|
+
gist.starred? #=> boolean
|
67
|
+
gist.star!
|
68
|
+
gist.unstar!
|
69
|
+
|
70
|
+
# Get a whole bunch of gists.
|
71
|
+
ActiveGist.all
|
72
|
+
ActiveGist.all :public # returns only public gists
|
73
|
+
ActiveGist.all :starred # returns only starred gists
|
74
|
+
|
75
|
+
# Get just one gist.
|
76
|
+
ActiveGist.first
|
77
|
+
ActiveGist.last
|
78
|
+
|
79
|
+
# Count gists.
|
80
|
+
ActiveGist.count
|
81
|
+
ActiveGist.count :public
|
82
|
+
ActiveGist.count :starred
|
83
|
+
|
84
|
+
# Save changes to a gist
|
85
|
+
gist = ActiveGist.first
|
86
|
+
gist.files['test.txt'][:content] = "Updated content"
|
87
|
+
gist.changed? #=> true
|
88
|
+
gist.save #=> true if saved, false if validation failed
|
89
|
+
gist.save! #=> true if saved, raise error if validation failed
|
90
|
+
|
91
|
+
# Destroy the gist, it's just a test gist anyway
|
92
|
+
gist.destroy
|
93
|
+
|
94
|
+
== Good Lovin'
|
95
|
+
|
96
|
+
Released under the MIT license. Copyright (c) 2012, Colin MacKenzie IV
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'active_gist/version'
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
RDoc::Task.new do |t|
|
9
|
+
t.rdoc_dir = 'doc'
|
10
|
+
t.title = "ActiveGist #{ActiveGist::VERSION} Documentation"
|
11
|
+
t.options << '--line-numbers'
|
12
|
+
t.rdoc_files.include('README.rdoc', 'CHANGELOG', 'LICENSE', 'lib/**/*.rb')
|
13
|
+
end
|
14
|
+
|
15
|
+
task :default => :spec
|
data/activegist.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "active_gist/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "activegist"
|
7
|
+
s.version = ActiveGist::VERSION
|
8
|
+
s.authors = ["Colin MacKenzie IV"]
|
9
|
+
s.email = ["sinisterchipmunk@gmail.com"]
|
10
|
+
s.homepage = "http://github.com/sinisterchipmunk/active-gist"
|
11
|
+
s.summary = %q{Wraps GitHub's Gist API with an intuitive class based on ActiveModel.}
|
12
|
+
s.description = %q{Wraps GitHub's Gist API with a class implementing the ActiveModel modules. So, it should be pretty familiar to anyone who's ever used models in Ruby on Rails.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "activegist"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rspec", '~> 2.8.0'
|
22
|
+
s.add_development_dependency "fakeweb", '~> 1.3.0'
|
23
|
+
s.add_development_dependency 'rake', "~> 0.9.2.2"
|
24
|
+
s.add_development_dependency 'rdoc', "~> 3.12"
|
25
|
+
|
26
|
+
s.add_runtime_dependency "activemodel", '~> 3.1.3'
|
27
|
+
s.add_runtime_dependency "activesupport", '~> 3.1.3'
|
28
|
+
s.add_runtime_dependency "rest-client", '~> 1.6.7'
|
29
|
+
end
|
data/lib/active_gist.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'active_support/hash_with_indifferent_access'
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class ActiveGist
|
7
|
+
autoload :Version, "active_gist/version"
|
8
|
+
autoload :VERSION, "active_gist/version"
|
9
|
+
autoload :API, "active_gist/api"
|
10
|
+
autoload :Attributes, "active_gist/attributes"
|
11
|
+
autoload :ClassMethods, "active_gist/class_methods"
|
12
|
+
autoload :Errors, "active_gist/errors/invalid"
|
13
|
+
autoload :Files, "active_gist/files"
|
14
|
+
|
15
|
+
extend ActiveModel::Naming
|
16
|
+
extend ActiveModel::Callbacks
|
17
|
+
include ActiveModel::Validations
|
18
|
+
include ActiveModel::Dirty
|
19
|
+
include ActiveModel::Conversion
|
20
|
+
include ActiveModel::Serializers::JSON
|
21
|
+
include ActiveModel::Serializers::Xml
|
22
|
+
|
23
|
+
include ActiveGist::API
|
24
|
+
include ActiveGist::Attributes
|
25
|
+
extend ActiveGist::API
|
26
|
+
extend ActiveGist::ClassMethods
|
27
|
+
|
28
|
+
define_model_callbacks :save, :create, :update, :initialize, :validation
|
29
|
+
validate { |record| record.errors.add(:files, "can't be blank") if record.files.empty? }
|
30
|
+
|
31
|
+
alias _changed? changed? #:nodoc:
|
32
|
+
def changed?
|
33
|
+
_changed? || files.changed?
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(attributes = {})
|
37
|
+
run_callbacks :initialize do
|
38
|
+
self.attributes = attributes
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def inspect
|
43
|
+
"#<#{self.class.name} #{attributes.collect { |a| [a[0], a[1].inspect].join('=') }.join(' ')}>"
|
44
|
+
end
|
45
|
+
|
46
|
+
def persisted?
|
47
|
+
!destroyed? && !id.blank? && !changed?
|
48
|
+
end
|
49
|
+
|
50
|
+
def new_record?
|
51
|
+
!destroyed? && id.blank?
|
52
|
+
end
|
53
|
+
|
54
|
+
def destroyed?
|
55
|
+
!!@destroyed
|
56
|
+
end
|
57
|
+
|
58
|
+
def destroy
|
59
|
+
api[id].delete :accept => 'application/json'
|
60
|
+
@id = nil
|
61
|
+
@destroyed = true
|
62
|
+
end
|
63
|
+
|
64
|
+
def fork
|
65
|
+
self.class.load(JSON.parse api[id]['fork'].post("", :accept => 'application/json'))
|
66
|
+
end
|
67
|
+
|
68
|
+
def files=(hash)
|
69
|
+
files.replace_with hash.with_indifferent_access
|
70
|
+
end
|
71
|
+
|
72
|
+
def files
|
73
|
+
@files ||= ActiveGist::Files.new
|
74
|
+
end
|
75
|
+
|
76
|
+
def ==(other)
|
77
|
+
other.kind_of?(ActiveGist) && id == other.id
|
78
|
+
end
|
79
|
+
|
80
|
+
def save
|
81
|
+
valid = begin
|
82
|
+
run_callbacks :validation do
|
83
|
+
valid?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
return false unless valid
|
88
|
+
|
89
|
+
create_or_update_callback = new_record? ? :create : :update
|
90
|
+
run_callbacks create_or_update_callback do
|
91
|
+
run_callbacks :save do
|
92
|
+
if new_record?
|
93
|
+
data = as_json(:only => [:description, :public, :files]).delete('active_gist').to_json
|
94
|
+
response = api.post data, :content_type => 'application/json', :accept => 'application/json'
|
95
|
+
else
|
96
|
+
data = as_json(:only => [:description, :files]).delete('active_gist').to_json
|
97
|
+
response = api[id].patch data, :content_type => 'application/json', :accept => 'application/json'
|
98
|
+
end
|
99
|
+
self.attributes = JSON.parse response
|
100
|
+
@previously_changed = changes
|
101
|
+
changed_attributes.clear
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
true
|
106
|
+
end
|
107
|
+
|
108
|
+
def save!
|
109
|
+
raise ActiveGist::Errors::Invalid, "Gist is invalid: #{errors.full_messages.join('; ')}" unless save
|
110
|
+
end
|
111
|
+
|
112
|
+
def starred?
|
113
|
+
if @star.nil?
|
114
|
+
@star = begin
|
115
|
+
@star = api[id]['star'].get :accept => 'application/json'
|
116
|
+
true
|
117
|
+
rescue RestClient::ResourceNotFound
|
118
|
+
false
|
119
|
+
end
|
120
|
+
else
|
121
|
+
@star
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def star!
|
126
|
+
api[id]['star'].put("", :accept => 'application/json')
|
127
|
+
@star = true
|
128
|
+
end
|
129
|
+
|
130
|
+
def unstar!
|
131
|
+
api[id]['star'].delete(:accept => 'application/json')
|
132
|
+
@star = false
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
|
3
|
+
module ActiveGist::API
|
4
|
+
class << self
|
5
|
+
def username
|
6
|
+
@username
|
7
|
+
end
|
8
|
+
|
9
|
+
def password
|
10
|
+
@password
|
11
|
+
end
|
12
|
+
|
13
|
+
def username=(username)
|
14
|
+
@username = username
|
15
|
+
end
|
16
|
+
|
17
|
+
def password=(password)
|
18
|
+
@password = password
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def username
|
23
|
+
ActiveGist::API.username
|
24
|
+
end
|
25
|
+
|
26
|
+
def password
|
27
|
+
ActiveGist::API.password
|
28
|
+
end
|
29
|
+
|
30
|
+
def api
|
31
|
+
@api ||= RestClient::Resource.new("https://api.github.com/gists", username, password)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module ActiveGist::Attributes
|
2
|
+
GIST_ATTRIBUTES = %w(url id description public user files comments
|
3
|
+
html_url git_pull_url git_push_url created_at
|
4
|
+
forks history updated_at)
|
5
|
+
|
6
|
+
def self.included(base) #:nodoc:
|
7
|
+
base.define_attribute_methods GIST_ATTRIBUTES
|
8
|
+
end
|
9
|
+
|
10
|
+
def forks
|
11
|
+
@forks
|
12
|
+
end
|
13
|
+
|
14
|
+
def history
|
15
|
+
@history
|
16
|
+
end
|
17
|
+
|
18
|
+
def url
|
19
|
+
@url
|
20
|
+
end
|
21
|
+
|
22
|
+
def id
|
23
|
+
@id
|
24
|
+
end
|
25
|
+
|
26
|
+
def description
|
27
|
+
@description
|
28
|
+
end
|
29
|
+
|
30
|
+
def public?
|
31
|
+
!!@public
|
32
|
+
end
|
33
|
+
alias public public?
|
34
|
+
|
35
|
+
def user
|
36
|
+
@user
|
37
|
+
end
|
38
|
+
|
39
|
+
def files
|
40
|
+
@files
|
41
|
+
end
|
42
|
+
|
43
|
+
def comments
|
44
|
+
@comments
|
45
|
+
end
|
46
|
+
|
47
|
+
def html_url
|
48
|
+
@html_url
|
49
|
+
end
|
50
|
+
|
51
|
+
def git_pull_url
|
52
|
+
@git_pull_url
|
53
|
+
end
|
54
|
+
|
55
|
+
def git_push_url
|
56
|
+
@git_push_url
|
57
|
+
end
|
58
|
+
|
59
|
+
def created_at
|
60
|
+
@created_at
|
61
|
+
end
|
62
|
+
|
63
|
+
def updated_at
|
64
|
+
@updated_at
|
65
|
+
end
|
66
|
+
|
67
|
+
def description=(descr)
|
68
|
+
description_will_change!
|
69
|
+
@description = descr
|
70
|
+
end
|
71
|
+
|
72
|
+
def public=(pub)
|
73
|
+
public_will_change!
|
74
|
+
@public = pub
|
75
|
+
end
|
76
|
+
|
77
|
+
def files=(files)
|
78
|
+
files_will_change!
|
79
|
+
@files = files
|
80
|
+
end
|
81
|
+
|
82
|
+
def attributes
|
83
|
+
GIST_ATTRIBUTES.inject({}) { |h,k| h[k] = self[k]; h }
|
84
|
+
end
|
85
|
+
|
86
|
+
def attributes=(attributes)
|
87
|
+
attributes.each do |key, value|
|
88
|
+
if respond_to?(:"#{key}=")
|
89
|
+
send :"#{key}=", value
|
90
|
+
else
|
91
|
+
if GIST_ATTRIBUTES.include?(key.to_s)
|
92
|
+
instance_variable_set :"@#{key}", value
|
93
|
+
else
|
94
|
+
raise ArgumentError, "Unknown attribute #{key.inspect}; expected one of #{GIST_ATTRIBUTES.inspect}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def [](attribute)
|
101
|
+
send attribute.to_sym
|
102
|
+
end
|
103
|
+
|
104
|
+
def []=(attribute, value)
|
105
|
+
send :"#{attribute}=", value
|
106
|
+
end
|
107
|
+
end
|