basuco 0.0.3

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.
@@ -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