basuco 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ test_log
2
+ pkg
3
+ pkg/*
4
+ */pkg/*
5
+ bundle
6
+ bundle/*
7
+ doc
8
+ *.log
9
+ log
10
+ !log*.rb
11
+ */log
12
+ log/*
13
+ */log/*
14
+ coverage
15
+ */coverage
16
+ lib/dm-more.rb
17
+ *.db
18
+ nbproject
19
+ .DS_Store
20
+ rspec_report.html
21
+ *.swp
22
+ _Yardoc
23
+ */ri
24
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in basuco.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael Aufreiter
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.
@@ -0,0 +1,318 @@
1
+ h1. Basuco (In Dev)
2
+
3
+ h2. Introduction
4
+
5
+ Basuco is a rails3 update in the form of a gem for the original Ken plugin.
6
+
7
+ It provides simple syntax to interact with the freebase api, and wraps responses in handy ruby objects.
8
+
9
+ h2. Installation
10
+
11
+ <pre>
12
+ <code>
13
+ $ gem install basuco
14
+ </code>
15
+ </pre>
16
+
17
+
18
+ h2. Getting started
19
+
20
+ The first place to get started with Freebase is of course, Freebase. Try out their Browser at
21
+ "http://www.freebase.com":http://www.freebase.com.
22
+
23
+ The Freebase Database can be thought of as a huge graph of interconnected nodes that represent
24
+ knowledge (in a much more structured way than wikipedia does).
25
+ That graph can be viewed at a higher level through an object-oriented lens which leads to easier interaction.
26
+ To understand the fundamental Metaweb Architecture please read the official
27
+ "MQL Reference guide":http://download.freebase.com/MQLReferenceGuide.pdf (with focus on Chapter 2)
28
+ provided by Freebase.
29
+
30
+ In addition, you can learn a lot by employing the Freebase "Query Editor":http://www.freebase.com/tools/queryeditor/.
31
+
32
+ With no registration you get 100K API calls per 24 hours, and more is available along with writing through registration.
33
+
34
+ h3. Fetching a Resource
35
+
36
+ Interaction with freebase occurs in three major ways.
37
+
38
+ First and most obvious is searching which will return collections built of resources, in turn built of properties.
39
+ <pre><code>x = Basuco::Search.new</code></pre>
40
+ Second is trans. The trans section is used for getting large chunks of text and images with their guid's.
41
+ <pre><code>x = Basuco::Trans.new</code></pre>
42
+ Lastly comes the Api for non-functional methods like logging in or checking the status of the api.
43
+ <pre><code>x = Basuco::Api.new</code></pre>
44
+
45
+ Lets start with an example:
46
+
47
+ <pre>
48
+ <code>
49
+ x = Basuco::Search.new
50
+ x.get('/en/new_order')
51
+ # => <Resource id="/en/new_order" name="New Order">
52
+ </code>
53
+ </pre>
54
+
55
+ h3. Inspecting the Types
56
+
57
+ Every Resource can have multiple types.
58
+
59
+ <pre>
60
+ <code>
61
+ resource.types
62
+ # => [ #<Type id="/film/music_contributor" name="Film music contributor">, #<Type id="/music/artist" name="Musical Artist">,
63
+ #<Type id="/common/topic" name="Topic">, #<Type id="/music/musical_group" name="Musical Group">,
64
+ #<Type id="/broadcast/artist" name="Broadcast Artist">, #<Type id="/music/group_member" name="Musical Group Member"> ]
65
+ </code>
66
+ </pre>
67
+
68
+ We can see that New Order is a member of Music Artist, Film Music Contributor, Broadcast Artist and other types.
69
+
70
+ h3. Inspecting a Type's properties
71
+
72
+ A type defines a set of properties to describe a Resource.
73
+
74
+ <pre>
75
+ <code>
76
+ resource.types.each do |type|
77
+ type.properties # => e.g. [ #<Property id="/music/musical_group/member"> ]
78
+ end
79
+ </code>
80
+ </pre>
81
+
82
+ We get sets of Properties for each Type. The Type Musical Group has just one Property @/music/musical_group/member@
83
+ named Members Of Musical Group.
84
+
85
+ h3. Listing all Attributes
86
+
87
+ After inspecting a Resource's Types and Properties we now know what we could know. But actually we don't know nothing :)
88
+ So it's time to ask for the values of properties, the so called _Attributes_.
89
+
90
+ ~Note: In Ken's terminology we differ between _Properties_ and concrete Property instances, the _Attributes_, while
91
+ Freebase itself doesn't.~
92
+
93
+ <pre>
94
+ <code>
95
+ resource.attributes.each do |att|
96
+ att # => e.g. #<Attribute property="/music/artist/album">
97
+ att.property.name # => e.g. "Albums"
98
+
99
+ att.values
100
+ # e.g. => [ #<Resource id="/guid/9202a8c04000641f8000000002fa2556" name="Ceremony">,
101
+ #<Resource id="/guid/9202a8c04000641f8000000002fa24d5" name="Procession">,
102
+ #<Resource id="/guid/9202a8c04000641f8000000002fa20d3" name="Everything's Gone Green">, ... ]
103
+ # e.g. => ["1980"]
104
+ end
105
+
106
+ # alternatively you can access them directly
107
+ resource.attribute('/music/artist/album') # => #<Attribute property="/music/artist/album">
108
+ </code>
109
+ </pre>
110
+
111
+ Attributes are slightly more complicated to handle compared to Types and Properties.
112
+
113
+ There are four kinds of Attributes.
114
+ * Unique Value Type
115
+ * Unique Object Type
116
+ * Non-unique Value Type
117
+ * Non-unique Object
118
+
119
+ In order to be able to use unique and non-unique Attributes in the same manner we always wrap the value of an Attribute
120
+ in a Collection, no matter if there's one value or there are many.
121
+
122
+ h3. Group Attributes by their Type using Views
123
+
124
+ <pre>
125
+ <code>
126
+ resource.views.each do |view|
127
+ view # => e.g. #<View type="/music/artist">
128
+ view.type # => e.g #<Type id="/music/artist" name="Musical Artist">
129
+ view.attributes
130
+ # => [#<Attribute property="/music/artist/home_page">, #<Attribute property="/music/artist/genre">,
131
+ #<Attribute property="/music/artist/active_start">, #<Attribute property="/music/artist/similar_artist">,
132
+ #<Attribute property="/music/artist/album">, #<Attribute property="/music/artist/label">,
133
+ #<Attribute property="/music/artist/track">, #<Attribute property="/music/artist/origin">]
134
+
135
+ view.attributes.each do |att|
136
+ att.values
137
+ # e.g. => [ #<Resource id="/en/alternative_dance" name="Alternative dance">,
138
+ #<Resource id="/en/synthpop" name="Synthpop">,
139
+ #<Resource id="/en/house_music" name="House music">,
140
+ #<Resource id="/en/post-punk" name="Post-punk"> ]
141
+ # e.g. => ["1980"]
142
+ end
143
+ end
144
+ </code>
145
+ </pre>
146
+
147
+ h3. Fetching multiple Resources using a query
148
+
149
+ As of now you can ask for multiple Resources by specifying a query.
150
+
151
+ <pre>
152
+ <code>
153
+ resources = Ken.all(:name => "Apple", :type => "/music/album")
154
+ # => [#<Resource id="/guid/9202a8c04000641f80000000031dae7c" name="Apple">,
155
+ #<Resource id="/guid/9202a8c04000641f8000000007ce31ec" name="Apple">]
156
+ </code>
157
+ </pre>
158
+
159
+ Keep in mind that only the top level of the query is mapped to a Collection of Resource Objects.
160
+ So asking for values in a nested level does not make sense. Use nested statements just for
161
+ lowering the top level result.
162
+
163
+ However you can instead navigate the normal way to figure out that values.
164
+ _But won't that require another query to triggered? Certainly._
165
+
166
+ Let's look at a nested query:
167
+
168
+ <pre>
169
+ <code>
170
+ query = {
171
+ :directed_by => "George Lucas",
172
+ :starring => [
173
+ {
174
+ :actor => "Harrison Ford"
175
+ }
176
+ ],
177
+ :type => "/film/film"
178
+ }
179
+
180
+ resources = Ken.all(query)
181
+ # => [#<Resource id="/en/star_wars_episode_iv_a_new_hope" name="Star Wars Episode IV: A New Hope">,
182
+ #<Resource id="/en/american_graffiti" name="American Graffiti">,
183
+ #<Resource id="/en/the_star_wars_holiday_special" name="The Star Wars Holiday Special">]
184
+ </code>
185
+ </pre>
186
+
187
+ h3. Access properties attributes directly
188
+
189
+ Ken is primarily designed for inspecting resources in a generic way, what's ideal for domain independent browsing applications.
190
+ However, there are legitimate situations where you already know what you want to access.
191
+
192
+ That's why I now added direct Property/Attribute access, but only on a Type/View level:
193
+
194
+ <pre>
195
+ <code>
196
+ resource = Ken.get('/en/new_order')
197
+ type = resource.types[1] # => #<Type id="/music/artist" name="Musical Artist">
198
+ # because we know _/music/artist_ has a _genre_ property we can access that directly
199
+ type.genre # => #<Property id="/music/artist/genre" expected_type="/music/genre" unique="false" object_type="true">
200
+ </code>
201
+ </pre>
202
+
203
+ The same works for views:
204
+
205
+ <pre>
206
+ <code>
207
+ resource = Ken.get('/en/new_order')
208
+ view = resource.views[1] # => #<View type="/music/artist">
209
+ # because we know _/music/artist_ has a _genre_ property we can access attribute directly as well
210
+ view.genre # => #<Attribute property="/music/artist/genre">
211
+ </code>
212
+ </pre>
213
+
214
+ If you rather want to query based on Types and access Properties/Attributes directly you can consider using
215
+ Chris "Eppsteins Freebase Library":http://github.com/chriseppstein/freebase/tree/master as an alternative.
216
+
217
+
218
+ h3. Low Level API
219
+
220
+ Sometimes you may want to do specific queries instead of inspecting Resources as a whole.
221
+ In such a case you would want to use Ken's low level API.
222
+
223
+ _mqlread_ works like the regular _mqlread service_, except that you are able to pass Ruby hashes instead of JSON.
224
+ And you don't have to deal with HTTP, parameter encoding and parsing JSON.
225
+
226
+ <pre>
227
+ <code>
228
+ artists = Ken.session.mqlread([{
229
+ :type => "/music/artist",
230
+ :id => nil,
231
+ :"/common/topic/webpage" => [{:uri => nil}],
232
+ :home_page => [{:uri => nil}],
233
+ :limit => 2
234
+ }])
235
+
236
+ # => [
237
+ {"type"=>"/music/artist", "home_page"=>[{"uri"=>"http://www.massiveattack.co.uk/"}], "id"=>"/en/massive_attack", "/common/topic/webpage"=>[{"uri"=>"http://musicmoz.org/Bands_and_Artists/M/Massive_Attack/"}, {"uri"=>"http://www.discogs.com/artist/Massive+Attack"}, {"uri"=>"http://www.massiveattackarea.com/"}, {"uri"=>"http://www.massiveattack.co.uk/"}, {"uri"=>"http://www.massiveattack.com/"}]},
238
+ {"type"=>"/music/artist", "home_page"=>[{"uri"=>"http://www.apartment26.com/"}], "id"=>"/en/apartment_26", "/common/topic/webpage"=>[{"uri"=>"http://www.discogs.com/artist/Apartment+26"}, {"uri"=>"http://musicmoz.org/Bands_and_Artists/A/Apartment_26/"}, {"uri"=>"http://www.apartment26.com/"}]}
239
+ ]
240
+ </code>
241
+ </pre>
242
+
243
+
244
+ h3. Topic API
245
+
246
+ Please first have a look at the official "Topic HTTP API documentation":http://www.freebase.com/docs/topic_api .
247
+
248
+ The API provides general meta-data such as name, description, links and images for a given topic,
249
+ as well as all properties directly related to that topic in the graph.
250
+ The API wraps a series of MQL queries that are needed to get this data, which otherwise must be performed separately.
251
+ So for gaining common interest information about a specific topic the Topic API is a way faster alternative to mqlread.
252
+
253
+ The latest update of Ken provides an easy way to access Freebase Topics using Ruby.
254
+ As usual Ken wraps the JSON result of the web service to convenient Ruby Objects.
255
+
256
+ For now Ken only returns simple properties. Support for so called mediator properties (aka 'CVT') will be added later.
257
+ To be honest, I just don't know how to wrap them appropriately using the existing Ken object model. Any API ideas are welcome, btw! ;)
258
+ However, in the meanwhile you can access CVT's by using the plain JSON result returned by the low level Ken.session.topic method.
259
+
260
+
261
+ The API for Topics is quite the same as for Resources.
262
+
263
+ <pre>
264
+ <code>
265
+ t = Ken::Topic.get("/en/new_order")
266
+ # => <Topic id="/en/new_order" name="New Order">
267
+
268
+ t.types
269
+ # => [ #<Type id="/music/artist" name="Musical Artist">, #<Type id="/music/musical_group" name="Musical Group">, ... ]
270
+
271
+ t.views
272
+ # => [ #<View type="/music/artist">, #<View type="/music/musical_group">, ... ]
273
+
274
+ t.properties
275
+ # => [ #<Property id="/music/artist/similar_artist" expected_type="/music/artist">, ... ]
276
+
277
+ t.attributes
278
+ # => [ #<Attribute property="/music/artist/similar_artist">, #<Attribute property="/music/artist/album">, ... ]
279
+
280
+ </code>
281
+ </pre>
282
+
283
+ Additionally you can access some general meta-data, most importantly the topic's description which otherwise would need an additional request to the raw service.
284
+
285
+ <pre>
286
+ <code>
287
+
288
+ t.name # => "New Order"
289
+ t.description # => "New Order were an English musical group formed in 1980 by Bernard Sumner ... "
290
+ t.aliases # => [ "NewOrder", "Englandneworder" ]
291
+ t.webpages # => [ {"url"=>"http://en.wikipedia.org/wiki/index.html?curid=22146", "text"=>"Wikipedia"}, ... ]
292
+ t.url # => "http://www.freebase.com/view/en/new_order"
293
+ t.thumbnail => "http://api.freebase.com/api/trans/image_thumb/en/new_order"
294
+
295
+ </code>
296
+ </pre>
297
+
298
+
299
+ h2. Project Status
300
+
301
+ h3. Features
302
+
303
+ * Fetching of single Resources
304
+ * Fetching of multiple Resources by specifying a query
305
+ * Accessing Properties/Attributes directly (on a type/view level)
306
+ * Type inspection
307
+ * Attribute inspection
308
+ * Low Level API (mqlread)
309
+ * Rails and Merb support
310
+ * Views on Resources to group Attributes based on the Resource's types
311
+ * Accessing Topics using the new Freebase Topic API
312
+
313
+ h3. Roadmap
314
+
315
+ # More tests
316
+ # Write-Support
317
+
318
+ Initial thoughts, obviously not up-to-date and not conforming to the current version, are available at "http://wiki.github.com/michael/ken":http://wiki.github.com/michael/ken.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "basuco/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "basuco"
7
+ s.version = Basuco::VERSION
8
+ s.authors = ["Caleb Bron"]
9
+ s.email = [""]
10
+ s.homepage = "https://github.com/cbron/basuco"
11
+ s.summary = %q{Freebase Gem}
12
+ s.description = %q{Transfer information from freebase.com through ruby.}
13
+
14
+ s.rubyforge_project = "basuco"
15
+
16
+ s.add_development_dependency "rspec"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ end
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'pathname'
3
+
4
+ EXAMPLES_ROOT = Pathname(__FILE__).dirname.expand_path
5
+ require EXAMPLES_ROOT.parent + 'lib/basuco'
6
+
7
+ session = Basuco::Search.new
8
+
9
+ resource = session.get('/en/tiesto') #basically everything starts with /en/
10
+
11
+ resource.views.each do |view|
12
+ puts view
13
+ puts "="*20
14
+ view.attributes.each do |a|
15
+ puts a.property
16
+ puts "-"*20
17
+ puts a
18
+ puts # newline
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+
4
+ # displays all links related to music/artists
5
+ # low level api through Ken.session.mqlread is used here
6
+
7
+ EXAMPLES_ROOT = Pathname(__FILE__).dirname.expand_path
8
+ require EXAMPLES_ROOT.parent + 'lib/ken'
9
+
10
+ Ken::Session.new('http://www.freebase.com', 'ma', '*****')
11
+
12
+ puts "collecting artist links... this might take a while..."
13
+
14
+ artist_links = []
15
+
16
+ # execute query
17
+ artists = Ken.session.mqlread([{
18
+ :type => "/music/artist",
19
+ :id => nil,
20
+ :"/common/topic/webpage" => [{:uri => nil}],
21
+ :home_page => [{:uri => nil}]
22
+ }], :cursor => true)
23
+
24
+ # collect artist links
25
+ artists.each do |artist|
26
+ artist["/common/topic/webpage"].each do |webpage|
27
+ artist_links << webpage["uri"] unless artist_links.include?(webpage["uri"])
28
+ end
29
+
30
+ artist["home_page"].each do |homepage|
31
+ artist_links << homepage["uri"] unless artist_links.include?(homepage["uri"])
32
+ end
33
+ end
34
+
35
+ # print artist links
36
+ artist_links.each do |link|
37
+ puts link
38
+ end