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 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
- ken.gemspec
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
- spec/mql_spec.rb
19
- spec/property_spec.rb
20
- spec/resource_spec.rb
21
- spec/session_spec.rb
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
- = Mql
1
+ = Ken
2
2
 
3
3
  * http://www.github.com/michael/ken
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- FIX (describe your package)
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
- * FIX (list of features or problems)
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
- FIX (code sample of usage)
40
+ resource = Ken.get('/en/new_order') # => <Resource id="/en/new_order" name="New Order">
16
41
 
17
42
  == REQUIREMENTS:
18
43
 
19
- * FIX (list of requirements)
44
+ - Ruby >=1.8.x
45
+ - RubyGems >=1.2.x
46
+ - Extlib >=0.9.x
20
47
 
21
48
  == INSTALL:
22
49
 
23
- * FIX (sudo gem install, anything else)
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.1'# Ken::VERSION
14
+ GEM_VERSION = '0.0.2'# Ken::VERSION
15
15
  GEM_DEPENDENCIES = [
16
16
  [ 'extlib', '>=0.9.10' ]
17
17
  # [ 'addressable', '~>2.0.1' ]
@@ -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
@@ -7,5 +7,10 @@ module Ken
7
7
  # def method_missing(name, *args, &blk)
8
8
  # @data.send name, *args, &blk
9
9
  # end
10
+
11
+ # add a linebreak after each entry
12
+ def to_s
13
+ self.inject("") { |m,i| "#{m}#{i.to_s}\n"}
14
+ end
10
15
  end
11
16
  end
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