activegist 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ html
6
+ doc
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - ree
6
+ - jruby
7
+ - ruby-head
8
+ - rbx-2.0
9
+
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ * 0.6.0 (01-15-2012)
2
+ * First release.
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in active_gist.gemspec
4
+ gemspec
5
+
6
+ gem 'json', :platforms => [ :ruby_18, :jruby ]
7
+ gem 'jruby-openssl', :platforms => :jruby
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
@@ -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
@@ -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