activegist 0.6.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.
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