html-schema 0.2.0
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/Rakefile +76 -0
- data/lib/html-schema.rb +83 -0
- data/lib/html-schema/api.rb +253 -0
- data/lib/html-schema/api/attribute.rb +54 -0
- data/lib/html-schema/api/object.rb +26 -0
- data/lib/html-schema/attribute.rb +43 -0
- data/lib/html-schema/configuration.rb +10 -0
- data/lib/html-schema/dsl.rb +23 -0
- data/lib/html-schema/helper.rb +10 -0
- data/lib/html-schema/microdata.rb +450 -0
- data/lib/html-schema/microdata/attribute.rb +9 -0
- data/lib/html-schema/microdata/object.rb +13 -0
- data/lib/html-schema/microformat.rb +218 -0
- data/lib/html-schema/microformat/attribute.rb +9 -0
- data/lib/html-schema/microformat/object.rb +9 -0
- data/lib/html-schema/object.rb +63 -0
- data/spec/schema_spec.rb +86 -0
- data/spec/spec_helper.rb +14 -0
- metadata +71 -0
data/Rakefile
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require "rake/rdoctask"
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = "html-schema"
|
7
|
+
s.authors = ["Lance Pollard"]
|
8
|
+
s.version = "0.2.0"
|
9
|
+
s.description = "Unified Ruby API for HTML5 Microdata and Microformats"
|
10
|
+
s.summary = "Unified Ruby API for HTML5 Microdata and Microformats"
|
11
|
+
s.homepage = "http://github.com/viatropos/html-schema"
|
12
|
+
s.email = "lancejpollard@gmail.com"
|
13
|
+
s.rubyforge_project = "html-schema"
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
s.files = %w(Rakefile) + Dir["{lib,rails,spec}/**/*"] - Dir["spec/tmp"]
|
16
|
+
s.require_path = "lib"
|
17
|
+
end
|
18
|
+
|
19
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
20
|
+
pkg.gem_spec = spec
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'run unit tests'
|
24
|
+
task :test do
|
25
|
+
Dir["test/**/*"].each do |file|
|
26
|
+
next unless File.basename(file) =~ /test_/
|
27
|
+
next unless File.extname(file) == ".rb"
|
28
|
+
system "ruby #{file}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Create .gemspec file (useful for github)"
|
33
|
+
task :gemspec do
|
34
|
+
File.open("#{spec.name}.gemspec", "w") do |f|
|
35
|
+
f.puts spec.to_ruby
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Build the gem into the current directory"
|
40
|
+
task :gem => :gemspec do
|
41
|
+
`gem build #{spec.name}.gemspec`
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Publish gem to rubygems"
|
45
|
+
task :publish => [:package] do
|
46
|
+
%x[gem push #{spec.name}-#{spec.version}.gem]
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Print a list of the files to be put into the gem"
|
50
|
+
task :manifest do
|
51
|
+
File.open("Manifest", "w") do |f|
|
52
|
+
spec.files.each do |file|
|
53
|
+
f.puts file
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "Install the gem locally"
|
59
|
+
task :install => [:package] do
|
60
|
+
File.mkdir("pkg") unless File.exists?("pkg")
|
61
|
+
command = "gem install pkg/#{spec.name}-#{spec.version} --no-ri --no-rdoc"
|
62
|
+
command = "sudo #{command}" if ENV["SUDO"] == true
|
63
|
+
sh %{#{command}}
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "Generate the rdoc"
|
67
|
+
Rake::RDocTask.new do |rdoc|
|
68
|
+
files = ["README.md", "lib/**/*.rb"]
|
69
|
+
rdoc.rdoc_files.add(files)
|
70
|
+
rdoc.main = "README.md"
|
71
|
+
rdoc.title = spec.summary
|
72
|
+
end
|
73
|
+
|
74
|
+
task :yank do
|
75
|
+
`gem yank #{spec.name} -v #{spec.version}`
|
76
|
+
end
|
data/lib/html-schema.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
$:.unshift File.dirname(File.expand_path(__FILE__)) + "/html-schema"
|
4
|
+
|
5
|
+
class HTMLSchema
|
6
|
+
class << self
|
7
|
+
def root
|
8
|
+
@root ||= File.dirname(File.expand_path(__FILE__))
|
9
|
+
end
|
10
|
+
|
11
|
+
def configure(&block)
|
12
|
+
yield configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
def configuration
|
16
|
+
@configuration ||= HTMLSchema::Configuration.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
api[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def instance
|
24
|
+
@instance ||= new
|
25
|
+
end
|
26
|
+
|
27
|
+
def instance=(value)
|
28
|
+
@instance = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def bootstrap!(format)
|
32
|
+
format_name = format == :api ? "API" : format.to_s.camelize
|
33
|
+
Dir["#{HTMLSchema.root}/html-schema/#{format}/**/*.rb"].inject({}) do |hash, file|
|
34
|
+
name = ::File.basename(file, File.extname(file))
|
35
|
+
hash[name.to_sym] = "::HTMLSchema::#{format_name}::#{name.camelize}".constantize.new if name !~ /^(base|feed|attribute)$/
|
36
|
+
hash
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(types = {})
|
42
|
+
self.class.instance = self
|
43
|
+
api.types.keys.each { |key| define_api_method(key) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def api
|
47
|
+
@api ||= HTMLSchema::API
|
48
|
+
end
|
49
|
+
|
50
|
+
def microdata
|
51
|
+
@microdata ||= HTMLSchema::Microdata
|
52
|
+
end
|
53
|
+
|
54
|
+
def microformat
|
55
|
+
@microformat ||= HTMLSchema::Microformat
|
56
|
+
end
|
57
|
+
|
58
|
+
# todo, iterate through tree, so you can visualize it however you want.
|
59
|
+
def each(&block)
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
def define_api_method(name)
|
65
|
+
self.class.send :define_method, name do
|
66
|
+
self.api[name]
|
67
|
+
end unless self.respond_to?(name)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
require 'object'
|
72
|
+
require 'attribute'
|
73
|
+
require 'configuration'
|
74
|
+
require 'dsl'
|
75
|
+
require 'api/object'
|
76
|
+
require 'api/attribute'
|
77
|
+
require 'microdata/object'
|
78
|
+
require 'microdata/attribute'
|
79
|
+
require 'microformat/object'
|
80
|
+
require 'microformat/attribute'
|
81
|
+
require 'api'
|
82
|
+
require 'microdata'
|
83
|
+
require 'microformat'
|
@@ -0,0 +1,253 @@
|
|
1
|
+
class HTMLSchema
|
2
|
+
class API
|
3
|
+
extend HTMLSchema::DSL
|
4
|
+
|
5
|
+
type :object do
|
6
|
+
attribute :id
|
7
|
+
attribute :title
|
8
|
+
attribute :name
|
9
|
+
attribute :url
|
10
|
+
attribute :description
|
11
|
+
attribute :image
|
12
|
+
|
13
|
+
type :address do
|
14
|
+
attribute :street
|
15
|
+
attribute :suite
|
16
|
+
attribute :city
|
17
|
+
attribute :state
|
18
|
+
attribute :country
|
19
|
+
attribute :postal_code
|
20
|
+
attribute :post_office_box
|
21
|
+
end
|
22
|
+
|
23
|
+
type :composition do
|
24
|
+
attribute :abstract, :type => [:person, :organization]
|
25
|
+
attribute :average_rating, :type => :rating
|
26
|
+
attribute :award
|
27
|
+
attribute :rating, :type => :rating
|
28
|
+
attribute :genre
|
29
|
+
attribute :headline
|
30
|
+
attribute :language
|
31
|
+
attribute :interaction_count
|
32
|
+
attribute :family_friendly, :type => :boolean
|
33
|
+
attribute :keyword
|
34
|
+
attribute :offer, :type => :offer
|
35
|
+
attribute :review, :type => :review
|
36
|
+
attribute :editor, :type => :person
|
37
|
+
attribute :author, :type => :person
|
38
|
+
attribute :organization, :type => :organization
|
39
|
+
attribute :publisher, :type => :organization
|
40
|
+
attribute :location, :type => :address
|
41
|
+
attribute :videa, :type => :media
|
42
|
+
attribute :encoding, :type => :media
|
43
|
+
attribute :audio, :type => :media
|
44
|
+
attribute :tag
|
45
|
+
attribute :published_at, :type => :date
|
46
|
+
|
47
|
+
type :article do
|
48
|
+
attribute :body
|
49
|
+
attribute :section
|
50
|
+
end
|
51
|
+
|
52
|
+
type :media do
|
53
|
+
attribute :bitrate
|
54
|
+
attribute :size
|
55
|
+
attribute :url
|
56
|
+
attribute :embed_url
|
57
|
+
attribute :composition, :type => :article
|
58
|
+
attribute :format
|
59
|
+
attribute :player
|
60
|
+
attribute :allowed_in, :type => :address
|
61
|
+
attribute :subscription_required, :type => :boolean
|
62
|
+
attribute :expires_at, :type => :date
|
63
|
+
attribute :uploaded_at, :type => :date
|
64
|
+
attribute :duration, :as => :measurement
|
65
|
+
attribute :height, :type => :measurement
|
66
|
+
attribute :width, :type => :measurement
|
67
|
+
|
68
|
+
type :audio
|
69
|
+
type :image
|
70
|
+
type :video
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
type :coordinates do
|
75
|
+
attribute :elevation, :type => :measurement
|
76
|
+
attribute :latitude
|
77
|
+
attribute :longitude
|
78
|
+
end
|
79
|
+
|
80
|
+
type :event do
|
81
|
+
attribute :child_event, :type => :event
|
82
|
+
attribute :parent_event, :type => :event
|
83
|
+
attribute :start_date, :type => :date
|
84
|
+
attribute :end_date, :type => :date
|
85
|
+
attribute :location, :type => :address
|
86
|
+
attribute :duration, :type => :measurement
|
87
|
+
attribute :offer, :type => :offer
|
88
|
+
attribute :attendee, :type => :person
|
89
|
+
attribute :performer, :type => :person
|
90
|
+
attribute :organization, :type => :organization
|
91
|
+
end
|
92
|
+
|
93
|
+
type :figure do
|
94
|
+
attribute :image
|
95
|
+
attribute :legend
|
96
|
+
attribute :author, :type => [:person, :organization]
|
97
|
+
attribute :subject
|
98
|
+
end
|
99
|
+
|
100
|
+
type :item do
|
101
|
+
attribute :type
|
102
|
+
attribute :value
|
103
|
+
end
|
104
|
+
|
105
|
+
type :measurement do
|
106
|
+
attribute :value
|
107
|
+
attribute :unit
|
108
|
+
attribute :item, :type => [:text, :person, :organization, :media, :event]
|
109
|
+
end
|
110
|
+
|
111
|
+
type :offer do
|
112
|
+
attribute :rating, :type => :rating
|
113
|
+
attribute :availability
|
114
|
+
attribute :condition
|
115
|
+
attribute :item, :type => :product
|
116
|
+
attribute :price, :type => :measurement
|
117
|
+
attribute :min_price, :type => :measurement
|
118
|
+
attribute :max_price, :type => :measurement
|
119
|
+
attribute :currency
|
120
|
+
attribute :valid_until_date, :type => :date
|
121
|
+
attribute :review, :type => :review
|
122
|
+
attribute :seller, :type => :organization
|
123
|
+
attribute :count
|
124
|
+
end
|
125
|
+
|
126
|
+
type :organization do
|
127
|
+
attribute :address, :type => :address
|
128
|
+
attribute :average_rating, :type => :rating
|
129
|
+
attribute :contact, :type => [:person, :organization]
|
130
|
+
attribute :email
|
131
|
+
attribute :employee, :type => :person
|
132
|
+
attribute :event, :type => :event
|
133
|
+
attribute :fax
|
134
|
+
attribute :founder, :type => :person
|
135
|
+
attribute :founded_at, :type => :date
|
136
|
+
|
137
|
+
type :vendor do
|
138
|
+
attribute :branch_of, :type => :organization
|
139
|
+
attribute :hours
|
140
|
+
attribute :currency
|
141
|
+
attribute :payment_method
|
142
|
+
attribute :price_range
|
143
|
+
attribute :menu
|
144
|
+
attribute :reservations
|
145
|
+
attribute :cuisine
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
type :person do
|
150
|
+
attribute :address, :type => :address
|
151
|
+
attribute :home_address, :type => :address
|
152
|
+
attribute :work_address, :type => :address
|
153
|
+
|
154
|
+
# organizations
|
155
|
+
attribute :organization, :type => :organization
|
156
|
+
attribute :education, :type => :organization
|
157
|
+
attribute :membership, :type => :organization
|
158
|
+
attribute :company, :type => :organization
|
159
|
+
|
160
|
+
# events
|
161
|
+
attribute :performer_in, :type => :event
|
162
|
+
|
163
|
+
# dates
|
164
|
+
attribute :born_at, :type => :date
|
165
|
+
attribute :died_at, :type => :date
|
166
|
+
|
167
|
+
# relationships
|
168
|
+
attribute :children, :type => :person
|
169
|
+
attribute :parents, :type => :person
|
170
|
+
attribute :siblings, :type => :person
|
171
|
+
attribute :spouse, :type => :person
|
172
|
+
attribute :relationship, :type => :person
|
173
|
+
attribute :colleagues, :type => :person
|
174
|
+
# unidirectional
|
175
|
+
attribute :follows, :type => :person
|
176
|
+
# bidirectional
|
177
|
+
attribute :knows, :type => :person
|
178
|
+
|
179
|
+
# info
|
180
|
+
attribute :contact_info, :type => :contact
|
181
|
+
attribute :email
|
182
|
+
attribute :phone
|
183
|
+
attribute :fax
|
184
|
+
attribute :gender
|
185
|
+
attribute :interaction_count
|
186
|
+
attribute :job_title
|
187
|
+
attribute :nationality, :type => :place
|
188
|
+
|
189
|
+
type :author
|
190
|
+
type :acquaintance
|
191
|
+
type :child
|
192
|
+
type :colleague
|
193
|
+
type :contact
|
194
|
+
type :roommate
|
195
|
+
type :coworker
|
196
|
+
type :crush
|
197
|
+
type :date
|
198
|
+
type :editor
|
199
|
+
type :fan
|
200
|
+
type :friend
|
201
|
+
type :kin
|
202
|
+
type :me
|
203
|
+
type :met
|
204
|
+
type :muse
|
205
|
+
type :neighbor
|
206
|
+
type :sibling
|
207
|
+
type :spouse
|
208
|
+
type :sweetheart
|
209
|
+
type :member
|
210
|
+
type :sponsor
|
211
|
+
type :user
|
212
|
+
end
|
213
|
+
|
214
|
+
type :place do
|
215
|
+
attribute :address, :type => :address
|
216
|
+
attribute :rating, :type => :rating
|
217
|
+
attribute :surrounding, :type => :place
|
218
|
+
attribute :event, :type => :event
|
219
|
+
attribute :fax
|
220
|
+
attribute :coordinates, :type => :coordinates
|
221
|
+
attribute :interaction_count
|
222
|
+
attribute :map
|
223
|
+
attribute :image, :type => :media
|
224
|
+
attribute :review, :type => :review
|
225
|
+
attribute :phone
|
226
|
+
end
|
227
|
+
|
228
|
+
type :product do
|
229
|
+
attribute :rating, :type => :rating
|
230
|
+
attribute :brand, :type => :organization
|
231
|
+
attribute :manufacturer, :type => :organization
|
232
|
+
attribute :model
|
233
|
+
attribute :offer, :type => :offer
|
234
|
+
attribute :review, :type => :review
|
235
|
+
end
|
236
|
+
|
237
|
+
type :rating do
|
238
|
+
attribute :best
|
239
|
+
attribute :value
|
240
|
+
attribute :worst
|
241
|
+
attribute :item, :type => [:person, :event, :media, :place, :organization]
|
242
|
+
attribute :rating_count
|
243
|
+
attribute :review_count
|
244
|
+
end
|
245
|
+
|
246
|
+
type :review do
|
247
|
+
attribute :body
|
248
|
+
attribute :item, :type => [:person, :event, :media, :place, :organization]
|
249
|
+
attribute :rating, :type => :rating
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class HTMLSchema
|
2
|
+
class API
|
3
|
+
class Attribute < HTMLSchema::Attribute
|
4
|
+
def microdata
|
5
|
+
if @microdata.nil?
|
6
|
+
object = HTMLSchema.instance.microdata[parent]
|
7
|
+
object = object[_name] if object
|
8
|
+
object = false if object.blank?
|
9
|
+
@microdata = object
|
10
|
+
end
|
11
|
+
|
12
|
+
@microdata
|
13
|
+
end
|
14
|
+
|
15
|
+
def microdata?
|
16
|
+
!!microdata
|
17
|
+
end
|
18
|
+
|
19
|
+
def microformat
|
20
|
+
if @microformat.nil?
|
21
|
+
object = HTMLSchema.instance.microformat[parent]
|
22
|
+
object = object[_name] if object
|
23
|
+
object = false if object.blank?
|
24
|
+
@microformat = object
|
25
|
+
end
|
26
|
+
@microformat
|
27
|
+
end
|
28
|
+
|
29
|
+
def microformat?
|
30
|
+
!!microformat
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_microdata
|
34
|
+
microdata.to_hash
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_microformat
|
38
|
+
microformat.to_hash
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_hash
|
42
|
+
if microdata? && microformat?
|
43
|
+
to_microdata.merge(to_microformat)
|
44
|
+
elsif microdata?
|
45
|
+
to_microdata
|
46
|
+
elsif microformat?
|
47
|
+
to_microformat
|
48
|
+
else
|
49
|
+
{}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|