michael-ken 0.0.1 → 0.0.2
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/Manifest.txt +16 -9
- data/README.textile +173 -0
- data/README.txt +34 -6
- data/Rakefile +1 -1
- data/examples/artist.rb +20 -0
- data/lib/ken.rb +17 -2
- data/lib/ken/attribute.rb +52 -0
- data/lib/ken/collection.rb +5 -0
- data/lib/ken/property.rb +56 -2
- data/lib/ken/resource.rb +129 -31
- data/lib/ken/session.rb +0 -2
- data/lib/ken/type.rb +14 -1
- data/lib/ken/util.rb +23 -0
- data/lib/ken/version.rb +1 -1
- data/lib/ken/view.rb +43 -0
- data/spec/fixtures/music_artist.json +102 -0
- data/spec/fixtures/the_police.json +891 -0
- data/spec/integration/ken_spec.rb +34 -0
- data/spec/spec_helper.rb +28 -1
- data/spec/unit/attribute_spec.rb +50 -0
- data/spec/unit/property_spec.rb +30 -0
- data/spec/unit/resource_spec.rb +63 -0
- data/spec/{session_spec.rb → unit/session_spec.rb} +1 -3
- data/spec/unit/type_spec.rb +21 -0
- data/spec/unit/view_spec.rb +26 -0
- data/tasks/gemspec.rb +23 -0
- metadata +16 -7
- data/.gitignore +0 -14
- data/ken.gemspec +0 -32
- data/spec/mql_spec.rb +0 -16
- data/spec/property_spec.rb +0 -0
- data/spec/resource_spec.rb +0 -28
data/Manifest.txt
CHANGED
@@ -1,27 +1,34 @@
|
|
1
|
-
.gitignore
|
2
1
|
History.txt
|
3
2
|
LICENSE
|
4
3
|
Manifest.txt
|
5
|
-
README.txt
|
6
4
|
README.textile
|
5
|
+
README.txt
|
7
6
|
Rakefile
|
8
7
|
TODO
|
9
|
-
|
8
|
+
examples/artist.rb
|
10
9
|
lib/ken.rb
|
10
|
+
lib/ken/attribute.rb
|
11
11
|
lib/ken/collection.rb
|
12
12
|
lib/ken/logger.rb
|
13
13
|
lib/ken/property.rb
|
14
14
|
lib/ken/resource.rb
|
15
15
|
lib/ken/session.rb
|
16
16
|
lib/ken/type.rb
|
17
|
+
lib/ken/util.rb
|
17
18
|
lib/ken/version.rb
|
18
|
-
|
19
|
-
spec/
|
20
|
-
spec/
|
21
|
-
spec/
|
22
|
-
spec/type_spec.rb
|
19
|
+
lib/ken/view.rb
|
20
|
+
spec/fixtures/music_artist.json
|
21
|
+
spec/fixtures/the_police.json
|
22
|
+
spec/integration/ken_spec.rb
|
23
23
|
spec/spec.opts
|
24
24
|
spec/spec_helper.rb
|
25
|
+
spec/unit/attribute_spec.rb
|
26
|
+
spec/unit/property_spec.rb
|
27
|
+
spec/unit/resource_spec.rb
|
28
|
+
spec/unit/session_spec.rb
|
29
|
+
spec/unit/type_spec.rb
|
30
|
+
spec/unit/view_spec.rb
|
31
|
+
tasks/gemspec.rb
|
25
32
|
tasks/hoe.rb
|
26
33
|
tasks/install.rb
|
27
|
-
tasks/spec.rb
|
34
|
+
tasks/spec.rb
|
data/README.textile
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
h1. Ken
|
2
|
+
|
3
|
+
h2. Introduction
|
4
|
+
|
5
|
+
Ken is a Data Layer for Knowledge Representation.
|
6
|
+
|
7
|
+
It's being built to access the Metaweb Services supplied by Freebase.com.
|
8
|
+
Just born, the project’s goals are the provision of a concise API for querying and writing.
|
9
|
+
Therefore it wraps the Metaweb Architecture to smart Ruby Objects (that represent the Metaweb Architecture).
|
10
|
+
|
11
|
+
You can navigate the Freebase Graph using a rubyish syntax.
|
12
|
+
|
13
|
+
You should be able to use this Library as a Data Layer (instead of or in addition to
|
14
|
+
ActiveRecord/DataMapper) for your Web Framework of choice (Merb, Rails).
|
15
|
+
|
16
|
+
|
17
|
+
h2. Installation
|
18
|
+
|
19
|
+
Use GitHub RubyGems.
|
20
|
+
|
21
|
+
<pre>
|
22
|
+
<code>
|
23
|
+
$ gem sources -a http://gems.github.com (you only have to do this once)
|
24
|
+
$ sudo gem install michael-ken
|
25
|
+
</code>
|
26
|
+
</pre>
|
27
|
+
|
28
|
+
Or even better, stay on The Edge.
|
29
|
+
|
30
|
+
|
31
|
+
h2. Getting started
|
32
|
+
|
33
|
+
The first place to get started with Freebase is of course, Freebase. Try out their Browser at
|
34
|
+
"http://www.freebase.com":http://www.freebase.com.
|
35
|
+
|
36
|
+
The Freebase Database can be thought of as a huge graph of interconnected nodes that represent
|
37
|
+
knowledge (in a much more structured way than wikipedia does).
|
38
|
+
That graph can be viewed at a higher level through an object-oriented lens which leads to easier interaction.
|
39
|
+
To understand the fundamental Metaweb Architecture please read the official
|
40
|
+
"MQL Reference guide":http://download.freebase.com/MQLReferenceGuide.pdf (with focus on Chapter 2)
|
41
|
+
provided by Freebase.
|
42
|
+
|
43
|
+
In addition, you can learn a lot by employing the Freebase "Query Editor":http://www.freebase.com/tools/queryeditor/.
|
44
|
+
|
45
|
+
h3. Fetching a Resource
|
46
|
+
|
47
|
+
Let's ask Ken what he knows about the British Band New Order.
|
48
|
+
|
49
|
+
<pre>
|
50
|
+
<code>
|
51
|
+
resource = Ken.get('/en/new_order') # => <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 types 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
|
+
h4. 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
|
+
</code>
|
106
|
+
</pre>
|
107
|
+
|
108
|
+
Attributes are slightly more complicated to handle compared to Types and Properties.
|
109
|
+
|
110
|
+
There are four kinds of Attributes.
|
111
|
+
* Unique Value Type
|
112
|
+
* Unique Object Type
|
113
|
+
* Non-unique Value Type
|
114
|
+
* Non-unique Object
|
115
|
+
|
116
|
+
In order to be able to use unique and non-unique Attributes in the same manner we always wrap the value of an Attribute
|
117
|
+
in a Collection, no matter if there's one value or there are many.
|
118
|
+
|
119
|
+
h4. Group Attributes by their Type using Views
|
120
|
+
|
121
|
+
|
122
|
+
<pre>
|
123
|
+
<code>
|
124
|
+
resource.views.each do |view|
|
125
|
+
view # => e.g. #<View type="/music/artist">
|
126
|
+
view.type # => e.g #<Type id="/music/artist" name="Musical Artist">
|
127
|
+
view.attributes
|
128
|
+
# => [#<Attribute property="/music/artist/home_page">, #<Attribute property="/music/artist/genre">,
|
129
|
+
#<Attribute property="/music/artist/active_start">, #<Attribute property="/music/artist/similar_artist">,
|
130
|
+
#<Attribute property="/music/artist/album">, #<Attribute property="/music/artist/label">,
|
131
|
+
#<Attribute property="/music/artist/track">, #<Attribute property="/music/artist/origin">]
|
132
|
+
|
133
|
+
view.attributes.each do |att|
|
134
|
+
att.values
|
135
|
+
# e.g. => [ #<Resource id="/en/alternative_dance" name="Alternative dance">,
|
136
|
+
#<Resource id="/en/synthpop" name="Synthpop">,
|
137
|
+
#<Resource id="/en/house_music" name="House music">,
|
138
|
+
#<Resource id="/en/post-punk" name="Post-punk"> ]
|
139
|
+
# e.g. => ["1980"]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
</code>
|
143
|
+
</pre>
|
144
|
+
|
145
|
+
h2. Status
|
146
|
+
|
147
|
+
Currently, the focus lies on inspecting Freebase Resources in a generic way. That's why
|
148
|
+
there is no support for accessing Properties or Attributes directly when you know them already.
|
149
|
+
That keeps me focussed and prevents me from adding too much sugar.
|
150
|
+
|
151
|
+
Therefore I would say that the first application using Ken will definitely be a Browser Application. :)
|
152
|
+
|
153
|
+
If you rather want to query based on Types and access Properties/Attributes directly you should consider using
|
154
|
+
Chris "Eppsteins Freebase Library":http://github.com/chriseppstein/freebase/tree/master instead.
|
155
|
+
|
156
|
+
h3. Features
|
157
|
+
|
158
|
+
* Fetching of single Resources
|
159
|
+
* Type inspection
|
160
|
+
* Attributes inspection
|
161
|
+
* Views on Resources to group Attributes based on the Resource's types
|
162
|
+
* Some specs
|
163
|
+
|
164
|
+
h3. Roadmap
|
165
|
+
|
166
|
+
# Much more specs
|
167
|
+
# Support for querying of multiple Resources
|
168
|
+
# Better Type Support
|
169
|
+
# API for Set Based Browsing (see http://mqlx.com/~david/parallax/)
|
170
|
+
# Accessing Properties/Attributes directly (e.g. resource.genres )
|
171
|
+
# Write-Support
|
172
|
+
|
173
|
+
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.
|
data/README.txt
CHANGED
@@ -1,26 +1,54 @@
|
|
1
|
-
=
|
1
|
+
= Ken
|
2
2
|
|
3
3
|
* http://www.github.com/michael/ken
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
|
7
|
+
Ken is a Data Layer for Knowledge Representation.
|
8
|
+
|
9
|
+
It's being built to access the Metaweb Services supplied by Freebase.com.
|
10
|
+
Just born, the project’s goals are the provision of a concise API for querying and writing.
|
11
|
+
Therefore it wraps the Metaweb Architecture to smart Ruby Objects (that represent the Metaweb Architecture).
|
12
|
+
|
13
|
+
You can navigate the Freebase Graph using a rubyish syntax.
|
14
|
+
|
15
|
+
You should be able to use this Library as a Data Layer (instead of or in addition to
|
16
|
+
ActiveRecord/DataMapper) for your Web Framework of choice (Merb, Rails).
|
17
|
+
|
8
18
|
|
9
19
|
== FEATURES/PROBLEMS:
|
10
20
|
|
11
|
-
|
21
|
+
Features
|
22
|
+
|
23
|
+
* Fetching of single Resources
|
24
|
+
* Type inspection
|
25
|
+
* Attributes inspection
|
26
|
+
* Views on Resources to group Attributes based on the Resource's types
|
27
|
+
* Some specs
|
28
|
+
|
29
|
+
Roadmap
|
30
|
+
|
31
|
+
1. Much more specs
|
32
|
+
2. Support for querying of multiple Resources
|
33
|
+
3. Better Type Support
|
34
|
+
4. API for Set Based Browsing (see http://mqlx.com/~david/parallax/)
|
35
|
+
5. Accessing Properties/Attributes directly (e.g. resource.genres )
|
36
|
+
6. Write-Support
|
12
37
|
|
13
38
|
== SYNOPSIS:
|
14
39
|
|
15
|
-
|
40
|
+
resource = Ken.get('/en/new_order') # => <Resource id="/en/new_order" name="New Order">
|
16
41
|
|
17
42
|
== REQUIREMENTS:
|
18
43
|
|
19
|
-
|
44
|
+
- Ruby >=1.8.x
|
45
|
+
- RubyGems >=1.2.x
|
46
|
+
- Extlib >=0.9.x
|
20
47
|
|
21
48
|
== INSTALL:
|
22
49
|
|
23
|
-
|
50
|
+
$ gem sources -a http://gems.github.com (you only have to do this once)
|
51
|
+
$ sudo gem install michael-ken
|
24
52
|
|
25
53
|
== LICENSE:
|
26
54
|
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ require ROOT + 'lib/ken/version'
|
|
11
11
|
AUTHOR = 'Michael Aufreiter'
|
12
12
|
EMAIL = 'ma[at]zive[dot]at'
|
13
13
|
GEM_NAME = 'ken'
|
14
|
-
GEM_VERSION = '0.0.
|
14
|
+
GEM_VERSION = '0.0.2'# Ken::VERSION
|
15
15
|
GEM_DEPENDENCIES = [
|
16
16
|
[ 'extlib', '>=0.9.10' ]
|
17
17
|
# [ 'addressable', '~>2.0.1' ]
|
data/examples/artist.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
EXAMPLES_ROOT = Pathname(__FILE__).dirname.expand_path
|
5
|
+
require EXAMPLES_ROOT.parent + 'lib/ken'
|
6
|
+
|
7
|
+
Ken::Session.new('http://www.freebase.com', 'ma', 'xxxxx')
|
8
|
+
|
9
|
+
resource = Ken.get('/en/the_police')
|
10
|
+
|
11
|
+
resource.views.each do |view|
|
12
|
+
puts view
|
13
|
+
puts "==============================="
|
14
|
+
view.attributes.each do |a|
|
15
|
+
puts a.property
|
16
|
+
puts "----------------"
|
17
|
+
puts a
|
18
|
+
puts # newline
|
19
|
+
end
|
20
|
+
end
|
data/lib/ken.rb
CHANGED
@@ -8,9 +8,12 @@ require 'addressable/uri'
|
|
8
8
|
dir = Pathname(__FILE__).dirname.expand_path + 'ken'
|
9
9
|
|
10
10
|
require dir + 'version'
|
11
|
+
require dir + 'util'
|
11
12
|
require dir + 'resource'
|
12
13
|
require dir + 'type'
|
14
|
+
require dir + 'view'
|
13
15
|
require dir + 'property'
|
16
|
+
require dir + 'attribute'
|
14
17
|
require dir + 'collection'
|
15
18
|
require dir + 'session'
|
16
19
|
require dir + 'logger'
|
@@ -18,13 +21,22 @@ require dir + 'logger'
|
|
18
21
|
# init logger as soon as the library is required
|
19
22
|
Ken::Logger.new(STDOUT, :error)
|
20
23
|
|
24
|
+
# init default session
|
25
|
+
Ken::Session.new('http://www.freebase.com', 'ma', 'xxxxx')
|
21
26
|
|
22
27
|
module Ken
|
23
28
|
def self.all(options = {})
|
24
|
-
#raise ArgumentError.new("must be a hash") unless options.is_a(::Hash)
|
29
|
+
# raise ArgumentError.new("must be a hash") unless options.is_a(::Hash)
|
25
30
|
raise NotImplementedError
|
26
31
|
end
|
27
32
|
|
33
|
+
|
34
|
+
# Executes an Mql Query against the Freebase API and returns the result wrapped
|
35
|
+
# in a <tt>Resource</tt> Object.
|
36
|
+
#
|
37
|
+
# == Examples
|
38
|
+
#
|
39
|
+
# Ken.get('/en/the_police') => #<Resource id="/en/the_police" name="The Police">
|
28
40
|
def self.get(id)
|
29
41
|
# TODO check if it has a correct /type/object/id syntax
|
30
42
|
raise ArgumentError.new("must be a string") unless id.is_a?(::String)
|
@@ -38,7 +50,10 @@ module Ken
|
|
38
50
|
:properties => [{
|
39
51
|
:id => nil,
|
40
52
|
:name => nil,
|
41
|
-
:expected_type => nil
|
53
|
+
:expected_type => nil,
|
54
|
+
:unique => nil,
|
55
|
+
:reverse_property => nil,
|
56
|
+
:master_property => nil,
|
42
57
|
}]
|
43
58
|
}]
|
44
59
|
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Ken
|
2
|
+
class Attribute
|
3
|
+
attr_reader :property
|
4
|
+
|
5
|
+
# initializes a resource by json result
|
6
|
+
def initialize(data, property)
|
7
|
+
raise "error" unless data.kind_of?(Array)
|
8
|
+
|
9
|
+
@data = data
|
10
|
+
@property = property # belongs to a property
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.create(data, property)
|
15
|
+
Ken::Attribute.new(data, property)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @api public
|
19
|
+
def to_s
|
20
|
+
subject.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api public
|
24
|
+
def inspect
|
25
|
+
result = "#<Attribute property=\"#{property.id || "nil"}\">"
|
26
|
+
end
|
27
|
+
|
28
|
+
# returns just the subject
|
29
|
+
def values
|
30
|
+
subject
|
31
|
+
end
|
32
|
+
|
33
|
+
def unique?
|
34
|
+
@property.unique?
|
35
|
+
end
|
36
|
+
|
37
|
+
def object_type?
|
38
|
+
@property.object_type?
|
39
|
+
end
|
40
|
+
|
41
|
+
# is this a good idea? using the values method seems more natural to me
|
42
|
+
# def method_missing(name, *args, &block)
|
43
|
+
# subject.send(name, *args, &block)
|
44
|
+
# end
|
45
|
+
|
46
|
+
# initializes the subject if used the first time
|
47
|
+
private
|
48
|
+
def subject
|
49
|
+
@subject ||= Ken::Collection.new(@data.map { |r| object_type? ? Ken::Resource.new(r) : r["value"] })
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/ken/collection.rb
CHANGED
data/lib/ken/property.rb
CHANGED
@@ -4,24 +4,78 @@ module Ken
|
|
4
4
|
# initializes a resource by json result
|
5
5
|
def initialize(data, type)
|
6
6
|
raise "error" unless data.kind_of?(Hash)
|
7
|
-
|
8
7
|
@data = data
|
9
8
|
@type = type
|
10
9
|
self
|
11
10
|
end
|
12
11
|
|
12
|
+
# @api public
|
13
13
|
def id
|
14
14
|
@data["id"]
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
|
+
# @api public
|
17
18
|
def name
|
18
19
|
@data["name"]
|
19
20
|
end
|
20
21
|
|
22
|
+
# @api public
|
23
|
+
def to_s
|
24
|
+
name || id || ""
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api public
|
28
|
+
def inspect
|
29
|
+
result = "#<Property id=\"#{id}\" expected_type=\"#{expected_type || "nil"}\" unique=\"#{unique?}\" object_type=\"#{object_type?}\">"
|
30
|
+
end
|
31
|
+
|
32
|
+
# returns the type of which the property is a part of
|
33
|
+
# every property always has exactly one type.
|
34
|
+
# that's why /type/property/schema is a unique property
|
35
|
+
# @api public
|
21
36
|
def type
|
22
37
|
@type
|
23
38
|
end
|
24
39
|
|
40
|
+
# @api public
|
41
|
+
def reverse_property
|
42
|
+
@data["reverse_property"]
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api public
|
46
|
+
def master_property
|
47
|
+
@data["master_property"]
|
48
|
+
end
|
49
|
+
|
50
|
+
# returns true if the property is unique
|
51
|
+
# @api public
|
52
|
+
def unique?
|
53
|
+
return @data["unique"]==true
|
54
|
+
end
|
55
|
+
|
56
|
+
# returns true if the property is an object type
|
57
|
+
# @api public
|
58
|
+
def object_type?
|
59
|
+
!%w{
|
60
|
+
/type/id
|
61
|
+
/type/int
|
62
|
+
/type/float
|
63
|
+
/type/boolean
|
64
|
+
/type/text
|
65
|
+
/type/rawstring
|
66
|
+
/type/uri
|
67
|
+
/type/datetime
|
68
|
+
/type/key
|
69
|
+
}.include?(expected_type)
|
70
|
+
end
|
71
|
+
|
72
|
+
# returns true if the property is a value type
|
73
|
+
# @api public
|
74
|
+
def value_type?
|
75
|
+
!object_type?
|
76
|
+
end
|
77
|
+
|
78
|
+
# @api public
|
25
79
|
def expected_type
|
26
80
|
@data["expected_type"]
|
27
81
|
end
|