nom_nom 0.0.4

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,8 @@
1
+ *~
2
+ *.bak
3
+ doc/api
4
+ doc/spec.html
5
+ pkg/*
6
+ doc
7
+ rdoc
8
+ .yardoc
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Nolan Eakins
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
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ Nom Nom
2
+ ===
3
+
4
+ C is for copyright. (C) 2010 [Nolan Eakins](mailto:sneakin+nomnom@semanticgap.com)
5
+
6
+
7
+ Intro
8
+ ---
9
+
10
+ NomNom is a consumer of RESTful APIs.
11
+
12
+ Status
13
+ ---
14
+
15
+ Currently, NomNom can only eat sugar cookie. Only the simplest APIs
16
+ are accessible, Twitter still bad for NomNom. NomNom no like Twitter.
17
+
18
+
19
+ Examples
20
+ ---
21
+
22
+ require 'nom_nom'
23
+
24
+ class Service < NomNom::Service
25
+ resources :posts
26
+ resources :users
27
+
28
+ class Post < NomNom::Resource
29
+ attr_accessor :id, :body, :user_id
30
+ belongs_to :user
31
+ end
32
+
33
+ class User < NomNom::Resource
34
+ attr_accessor :id, :login, :email
35
+ has_many :posts
36
+ end
37
+ end
38
+
39
+ s = Service.new('https://example.com', 'user', 'password')
40
+ s.users.each do |u|
41
+ puts u.login
42
+ puts '=' * u.login.length
43
+ puts "\t" + u.posts.collect { |p| p.body }.join("\n\t")
44
+ end
45
+
46
+
47
+ More for [Bitter](http://bitter.rubyforge.org/) and [Syncd](http://www.syncd.com/) can be found in [`./examples`](http://github.com/sneakin/nom-nom/tree/master/examples/).
48
+
49
+
50
+ License
51
+ ===
52
+
53
+ Copyright (c) 2010 Nolan Eakins
54
+
55
+ Permission is hereby granted, free of charge, to any person obtaining
56
+ a copy of this software and associated documentation files (the
57
+ "Software"), to deal in the Software without restriction, including
58
+ without limitation the rights to use, copy, modify, merge, publish,
59
+ distribute, sublicense, and/or sell copies of the Software, and to
60
+ permit persons to whom the Software is furnished to do so, subject to
61
+ the following conditions:
62
+
63
+ The above copyright notice and this permission notice shall be
64
+ included in all copies or substantial portions of the Software.
65
+
66
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
67
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
68
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
69
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
70
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
71
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
72
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "nom_nom"
8
+ gem.summary = %Q{COOKIE!!}
9
+ gem.description = %Q{I consume web service. Nom nom nom.}
10
+ gem.email = "sneakin+nomnom@semanticgap.com"
11
+ gem.homepage = "http://github.com/sneakin/nom-nom"
12
+ gem.authors = ["Nolan Eakins"]
13
+ gem.add_development_dependency "rspec"
14
+ gem.add_dependency('nokogiri', '= 1.4.3.1')
15
+ gem.add_dependency('httparty', '= 0.6.1')
16
+ gem.add_dependency('active_support', '= 3.0.0')
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
+ end
23
+
24
+ require 'spec/rake/spectask'
25
+ Spec::Rake::SpecTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.spec_files = FileList['spec/**/*_spec.rb']
28
+ end
29
+
30
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.pattern = 'spec/**/*_spec.rb'
33
+ spec.rcov = true
34
+ end
35
+
36
+ task :spec => :check_dependencies
37
+
38
+ task :default => :spec
39
+
40
+ require 'rake/rdoctask'
41
+ Rake::RDocTask.new do |rdoc|
42
+ if File.exist?('VERSION')
43
+ version = File.read('VERSION')
44
+ else
45
+ version = ""
46
+ end
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "nom_nom #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
53
+
54
+ require 'yard'
55
+ require 'yard/rake/yardoc_task'
56
+
57
+ desc 'Generate Yardoc documentation'
58
+ YARD::Rake::YardocTask.new do |yardoc|
59
+ yardoc.name = 'doc'
60
+ yardoc.options = ['--verbose']
61
+ yardoc.files = [ 'lib/**/*.rb', 'examples/**/*.rb', 'LICENSE', 'README.md' ]
62
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
@@ -0,0 +1,20 @@
1
+ require 'nom_nom'
2
+
3
+ class Bitter < NomNom::Service
4
+ class Bit < NomNom::Resource
5
+ attr_accessor :id, :body, :user_id, :created_on, :updated_on
6
+ belongs_to :user
7
+ end
8
+
9
+ class User < NomNom::Resource
10
+ attr_accessor :id, :login
11
+ has_many :bits
12
+ end
13
+
14
+ def initialize(url, user, pass)
15
+ super(url, user, pass, Bitter)
16
+ end
17
+
18
+ resources :bits
19
+ resources :users
20
+ end
data/examples/syncd.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'nom_nom'
2
+
3
+ module Syncd
4
+ class Account < NomNom::Service
5
+ def initialize(subdomain, user, pass)
6
+ super("https://#{subdomain}.syncd.com", user, pass, Syncd)
7
+ end
8
+
9
+ resources :activities
10
+ resources :jobs
11
+ resources :job_types
12
+ resources :time_entries
13
+ resources :users
14
+
15
+ def time_entry_summary(query = Hash.new)
16
+ get("/time_entries/summary.xml", :query => query)['time_summary']
17
+ end
18
+ end
19
+
20
+ class Activity < NomNom::Resource
21
+ attr_accessor :id, :name, :active, :code, :description, :url, :created_at, :updated_at
22
+
23
+ has_many :time_entries
24
+ end
25
+
26
+ class TimeEntry < NomNom::Resource
27
+ attr_accessor :id, :duration, :start_time, :end_time, :note, :user_id, :job_id, :activity_id, :created_at, :updated_at
28
+
29
+ belongs_to :user
30
+ belongs_to :job
31
+ belongs_to :activity
32
+ end
33
+
34
+ class Job < NomNom::Resource
35
+ attr_accessor :id, :job_type_id, :parent_id, :name, :code, :description, :url, :active, :effectively_active, :allow_time_entries, :allow_expense_entries, :assigned
36
+
37
+ belongs_to :job_type
38
+ belongs_to :parent, :class_name => self.name.demodulize, :key => :parent_id
39
+
40
+ def ancestors
41
+ return [ self, *parent.ancestors ] if parent_id
42
+ return [ self ]
43
+ end
44
+ end
45
+
46
+ class JobType < NomNom::Resource
47
+ attr_accessor :id, :parent_id, :name, :name_plural, :allow_time_entries, :allow_expense_entries, :show_codes, :show_links, :show_descriptions, :levels
48
+
49
+ belongs_to :parent, :class_name => self.name.demodulize
50
+ has_many :children, :class_name => self.name.demodulize, :key => :parent_id
51
+
52
+ def ancestors
53
+ return [ self, *parent.ancestors ] if parent_id
54
+ return [ self ]
55
+ end
56
+ end
57
+
58
+ class User < NomNom::Resource
59
+ attr_accessor :id, :name, :first_name, :last_name, :active, :code, :email, :url, :created_at, :updated_at
60
+
61
+ has_many :time_entries
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ module NomNom
2
+ class Resource
3
+ attr_reader :service
4
+
5
+ def initialize(service, attrs)
6
+ @service = service
7
+
8
+ attrs.each { |attr, value|
9
+ if respond_to?("#{attr}=")
10
+ send("#{attr}=", value)
11
+ else
12
+ $stderr.puts "WARNING: #{attr} is undefined for #{self.class}"
13
+ end
14
+ }
15
+ end
16
+
17
+ def ==(other)
18
+ self.id == other.id
19
+ end
20
+
21
+ class << self
22
+ def belongs_to(name, options = {})
23
+ assoc = (options[:class_name] || name).to_s.underscore.pluralize
24
+ key = options[:key] || "#{name}_id"
25
+
26
+ define_method(name) do |*args|
27
+ service.send(assoc, *args).find { |r| r.id == send(key) }
28
+ end
29
+ end
30
+
31
+ def has_many(name, options = {})
32
+ assoc = (options[:class_name] || name).to_s.underscore.pluralize
33
+ key = options[:key] || "#{self.name.demodulize.underscore}_id"
34
+
35
+ define_method(name) do |*args|
36
+ service.send(assoc, *args).select { |r| r.send(key) == id }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,53 @@
1
+ module NomNom
2
+ class Service
3
+ include HTTParty
4
+
5
+ attr_reader :auth, :module
6
+
7
+ def initialize(uri, user, pass, mod = self.class.name)
8
+ self.class.base_uri uri
9
+ @auth = { :username => user, :password => pass } if user
10
+ @module = mod.to_s.camelize
11
+ end
12
+
13
+ def get(path, options = Hash.new)
14
+ ret = self.class.get(path, { :basic_auth => @auth }.merge(options))
15
+ $stderr.puts path.inspect, ret.inspect
16
+ ret
17
+ end
18
+
19
+ class << self
20
+ def resources(name, options = Hash.new)
21
+ name = name.to_s
22
+ path = options[:path] || "/#{name}.xml"
23
+
24
+ define_method(name) do |*args|
25
+ query = args.extract_options!
26
+ reload = args[0] || false
27
+
28
+ if !query.empty? || reload || instance_variable_get("@#{name}") == nil
29
+ resources = get_resources(path, query, name)
30
+
31
+ if query.empty?
32
+ instance_variable_set("@#{name}", resources)
33
+ else
34
+ return resources
35
+ end
36
+ end
37
+
38
+ instance_variable_get("@#{name}")
39
+ end
40
+ end
41
+ end
42
+
43
+ protected
44
+ def get_resources(path, query, resource)
45
+ $stderr.puts(path.inspect)
46
+ klass = ("#{@module}::" + resource.to_s.singularize.camelize).constantize
47
+
48
+ self.
49
+ get(path, :query => query)[resource].
50
+ collect { |r| klass.new(self, r) }
51
+ end
52
+ end
53
+ end
data/lib/nom_nom.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'active_support'
2
+ require 'active_support/inflector'
3
+ require 'active_support/core_ext'
4
+ require 'httparty'
5
+ require 'nokogiri'
6
+
7
+ module NomNom
8
+ require 'nom_nom/service'
9
+ require 'nom_nom/resource'
10
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "NomNom" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'nom_nom'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nom_nom
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 4
10
+ version: 0.0.4
11
+ platform: ruby
12
+ authors:
13
+ - Nolan Eakins
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-26 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: nokogiri
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - "="
42
+ - !ruby/object:Gem::Version
43
+ hash: 113
44
+ segments:
45
+ - 1
46
+ - 4
47
+ - 3
48
+ - 1
49
+ version: 1.4.3.1
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: httparty
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - "="
59
+ - !ruby/object:Gem::Version
60
+ hash: 5
61
+ segments:
62
+ - 0
63
+ - 6
64
+ - 1
65
+ version: 0.6.1
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: active_support
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - "="
75
+ - !ruby/object:Gem::Version
76
+ hash: 7
77
+ segments:
78
+ - 3
79
+ - 0
80
+ - 0
81
+ version: 3.0.0
82
+ type: :runtime
83
+ version_requirements: *id004
84
+ description: I consume web service. Nom nom nom.
85
+ email: sneakin+nomnom@semanticgap.com
86
+ executables: []
87
+
88
+ extensions: []
89
+
90
+ extra_rdoc_files:
91
+ - LICENSE
92
+ - README.md
93
+ files:
94
+ - .gitignore
95
+ - LICENSE
96
+ - README.md
97
+ - Rakefile
98
+ - VERSION
99
+ - examples/bitter.rb
100
+ - examples/syncd.rb
101
+ - lib/nom_nom.rb
102
+ - lib/nom_nom/resource.rb
103
+ - lib/nom_nom/service.rb
104
+ - spec/nom_nom_spec.rb
105
+ - spec/spec_helper.rb
106
+ has_rdoc: true
107
+ homepage: http://github.com/sneakin/nom-nom
108
+ licenses: []
109
+
110
+ post_install_message:
111
+ rdoc_options:
112
+ - --charset=UTF-8
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
123
+ version: "0"
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: 3
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ requirements: []
134
+
135
+ rubyforge_project:
136
+ rubygems_version: 1.3.7
137
+ signing_key:
138
+ specification_version: 3
139
+ summary: COOKIE!!
140
+ test_files:
141
+ - spec/nom_nom_spec.rb
142
+ - spec/spec_helper.rb
143
+ - examples/bitter.rb
144
+ - examples/syncd.rb