yql 0.0.1

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,4 @@
1
+ === 0.1.1 2010-06-20
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -0,0 +1,7 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ lib/yql.rb
5
+ lib/yql/client.rb
6
+ lib/yql/error.rb
7
+ lib/yql/query_builder.rb
@@ -0,0 +1,105 @@
1
+ ==DESCRIPTION
2
+
3
+ A basic Ruby Wrapper for interacting programatically with YQL API.
4
+
5
+
6
+ ==TODO
7
+
8
+ 1. Add Unit Tests
9
+ 2. Add oauth
10
+ 3. Add table creation
11
+ 4. Add update / insert / delete operations
12
+
13
+ ==INSTALLATION
14
+
15
+ sudo gem source --add http://rubygems.org
16
+
17
+ sudo gem install yql
18
+
19
+
20
+ ==USAGE
21
+
22
+ require 'rubygems'
23
+
24
+ require 'yql'
25
+
26
+ ===Building Query
27
+
28
+
29
+ ====Finders
30
+
31
+ yql = Yql::Client.new
32
+
33
+ query = Yql::QueryBuilder.new 'yelp.review.search'
34
+
35
+ query.to_s #=> "select * from yelp.review.search"
36
+
37
+ query.find #=> "select * from yelp.review.search limit 1"
38
+
39
+ query.limit = 4
40
+
41
+ query.to_s #=> "select * from yelp.review.search limit 4"
42
+
43
+ query.find_all #=> "select * from yelp.review.search"
44
+
45
+
46
+ ====Conditions
47
+
48
+ query.conditions = "term like '%pizza%'"
49
+
50
+ query.to_s #=> "select * from yelp.review.search where term='%pizza%'"
51
+
52
+ query.conditions = {:term => 'pizza'}
53
+
54
+ query.to_s #=> "select * from yelp.review.search where term = 'pizza'"
55
+
56
+ query.conditions = {:term => 'pizza', :location => 'london', 'ywsid' => '6L0Lc-yn1OKMkCKeXLD4lg'}
57
+
58
+ query.to_s #=> "select * from yelp.review.search where term='pizza' and location='london' and ywsid= '6L0Lc-yn1OKMkCKeXLD4lg'"
59
+
60
+ query.select = 'user_photo_url, state'
61
+
62
+ yql.query = query
63
+ response = yql.get
64
+
65
+ yql.format = 'json'
66
+ response = yql.get #=> Yql::Response object
67
+
68
+
69
+ ===Piped Filters
70
+
71
+ query.unique = 'name'
72
+
73
+ query.to_s #=> "select title, Rating, LastReviewIntro from yelp.review.search where ywsid='6L0Lc-yn1OKMkCKeXLD4lg' and term='pizza' and location='london' | unique(field='name')"
74
+
75
+ query.tail = 4
76
+
77
+ query.to_s #=> "select title, Rating, LastReviewIntro from yelp.review.search where ywsid='6L0Lc-yn1OKMkCKeXLD4lg' and term='pizza' and location='london' | unique(field='name') | tail(count=4)"
78
+
79
+ query.reorder_pipe_command :from => 1, :to => 0
80
+
81
+ query.to_s #=> "select title, Rating, LastReviewIntro from yelp.review.search where ywsid='6L0Lc-yn1OKMkCKeXLD4lg' and term='pizza' and location='london' | tail(count=4) | unique(field='name')"
82
+
83
+ yql.format = 'json'
84
+ response = yql.get #=> Yql::Response object
85
+
86
+
87
+ ====Pagination
88
+
89
+ query.per_page = 10
90
+ query.current_page = 1
91
+
92
+ yql.query = query
93
+ response = yql.get #=> Yql::Response object
94
+
95
+
96
+ ===Describe and show tables
97
+
98
+ query = Yql::QueryBuilder.describe_table('yelp.review.search')
99
+
100
+ query = Yql::QueryBuilder.show_tables
101
+
102
+ yql.query = query
103
+ response = yql.get #=> Yql::Response object
104
+
105
+ response.show
@@ -0,0 +1,12 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'CGI'
6
+ require 'net/http'
7
+ require 'net/https'
8
+ require 'rexml/document'
9
+ require 'yql/error.rb'
10
+ require 'yql/client.rb'
11
+ require 'yql/query_builder.rb'
12
+ require 'yql/response.rb'
@@ -0,0 +1,61 @@
1
+ module Yql
2
+
3
+ class Client
4
+
5
+ BASE_URL = 'query.yahooapis.com'
6
+ VERSION = 'v1'
7
+ URL_SUFFIX = 'public/yql'
8
+ YQL_ENV = 'http://datatables.org/alltables.env'
9
+
10
+ attr_accessor :query, :diagnostics, :format
11
+
12
+ def initialize(args={})
13
+ @diagnostics = args[:diagnostics] #true or false
14
+ @version = args[:version]
15
+ @query = args[:query]
16
+ @format = args[:format] || 'xml'
17
+ end
18
+
19
+ def query
20
+ @query.kind_of?(Yql::QueryBuilder) ? @query.to_s : @query
21
+ end
22
+
23
+ def version
24
+ @version ||= VERSION
25
+ end
26
+
27
+ def full_url
28
+ "#{version}/#{URL_SUFFIX}"
29
+ end
30
+
31
+ def get
32
+ if query.nil?
33
+ raise Yql::IncompleteRequestParameter, "Query not specified"
34
+ end
35
+ http = Net::HTTP.new(BASE_URL, Net::HTTP.https_default_port)
36
+ http.use_ssl = true
37
+ path = "/#{version}/#{URL_SUFFIX}"
38
+ Yql::Response.new(http.post(path, parameters), format)
39
+ end
40
+
41
+ def parameters
42
+ url_parameters = "q=#{CGI.escape(query)}&env=#{YQL_ENV}"
43
+ url_parameters = add_format(url_parameters)
44
+ add_diagnostics(url_parameters)
45
+ end
46
+
47
+ def add_format(existing_parameters)
48
+ return unless existing_parameters
49
+ return existing_parameters unless format
50
+ return existing_parameters + "&format=#{format}"
51
+ end
52
+
53
+ def add_diagnostics(existing_parameters)
54
+ return unless existing_parameters
55
+ return existing_parameters unless diagnostics
56
+ return existing_parameters + "&diagnostics=true"
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,19 @@
1
+ module Yql
2
+ class Error < StandardError
3
+
4
+ def initialize(data)
5
+ @data = data
6
+ super
7
+ end
8
+ end
9
+
10
+ class ResponseFailure < Error
11
+ end
12
+
13
+ class NoResult < Error
14
+ end
15
+
16
+ class IncompleteRequestParameter < Error
17
+ end
18
+
19
+ end
@@ -0,0 +1,186 @@
1
+ module Yql
2
+
3
+ class QueryBuilder
4
+
5
+ attr_accessor :table, :conditions, :limit, :truncate, :sanitize_field, :select,
6
+ :sort_field, :current_pipe_command_types, :sort_descending,
7
+ :per_page, :current_page
8
+
9
+ def initialize(table, args = {})
10
+ @select = args[:select]
11
+ @table = table
12
+ @use_statement = args[:use]
13
+ @conditions = args[:conditions]
14
+ @limit = args[:limit]
15
+ @tail = args[:tail]
16
+ @reverse = args[:reverse]
17
+ @unique = args[:unique]
18
+ @sanitize = args[:sanitize]
19
+ @sort_descending = args[:sort_descending]
20
+ @sanitize_field = args[:sanitize_field]
21
+ @sort_field = args[:sort_field]
22
+ @current_pipe_command_types = []
23
+ @per_page = args[:per_page]
24
+ end
25
+
26
+ def find
27
+ self.limit = 1
28
+ "#{construct_query}"
29
+ end
30
+
31
+ def find_all
32
+ self.limit = nil
33
+ construct_query
34
+ end
35
+
36
+ def self.show_tables
37
+ "show tables;"
38
+ end
39
+
40
+ def self.describe_table(table)
41
+ "desc #{table};"
42
+ end
43
+
44
+ def describe_table
45
+ Yql::QueryBuilder.describle_table(table)
46
+ end
47
+
48
+ def to_s
49
+ construct_query
50
+ end
51
+
52
+ def limit
53
+ return unless @limit
54
+ "limit #{@limit}"
55
+ end
56
+
57
+ # Conditions can either be provided as hash or plane string
58
+ def conditions
59
+ if @conditions.kind_of?(String)
60
+ cond = @conditions
61
+ elsif @conditions.kind_of?(Hash)
62
+ cond = @conditions.collect do |k,v|
63
+ val = v.kind_of?(String) ? "'#{v}'" : v
64
+ "#{k.to_s}=#{val}"
65
+ end
66
+ cond = cond.join(' and ')
67
+ else
68
+ return
69
+ end
70
+ return "where #{cond}"
71
+ end
72
+
73
+ %w{sort tail truncate reverse unique sanitize}.each do |method|
74
+ self.send(:define_method, "#{method}=") do |param|
75
+ instance_variable_set("@#{method}", param)
76
+ current_pipe_command_types << method unless current_pipe_command_types.include?(method)
77
+ end
78
+ end
79
+
80
+ # Cption can be piped
81
+ # Sorts the result set according to the specified field (column) in the result set.
82
+ def sort
83
+ return unless @sort_field
84
+ return "sort(field='#{@sort_field}')" unless @sort_descending
85
+ return "sort(field='#{@sort_field}', descending='true')"
86
+ end
87
+
88
+ # Cption can be piped
89
+ # Gets the last count items
90
+ def tail
91
+ return unless @tail
92
+ "tail(count=#{@tail})"
93
+ end
94
+
95
+ # Cption can be piped
96
+ # Gets the first count items (rows)
97
+ def truncate
98
+ return unless @truncate
99
+ "truncate(count=#{@truncate})"
100
+ end
101
+
102
+ # Cption can be piped
103
+ # Reverses the order of the rows
104
+ def reverse
105
+ return unless @reverse
106
+ "reverse()"
107
+ end
108
+
109
+ # Cption can be piped
110
+ # Removes items (rows) with duplicate values in the specified field (column)
111
+ def unique
112
+ return unless @unique
113
+ "unique(field='#{@unique}')"
114
+ end
115
+
116
+ # Cption can be piped
117
+ # Sanitizes the output for HTML-safe rendering. To sanitize all returned fields, omit the field parameter.
118
+ def sanitize
119
+ return unless @sanitize
120
+ return "sanitize()" unless @sanitize_field
121
+ "sanitize(field='#{@sanitize_field}')"
122
+ end
123
+
124
+ # Its always advisable to order the pipe when there are more than one
125
+ # pipe commands available else unexpected results might get returned
126
+ # reorder_pipe_command {:from => 1, :to => 0}
127
+ # the values in the hash are the element numbers
128
+ #
129
+ def reorder_pipe_command(args)
130
+ return if current_pipe_command_types.empty?
131
+ if args[:from].nil? or args[:to].nil?
132
+ raise Yql::Error, "Not able to move pipe commands. Wrong element numbers. Please try again"
133
+ end
134
+ args.values.each do |element|
135
+ if element > current_pipe_command_types.size-1
136
+ raise Yql::Error, "Not able to move pipe commands. Wrong element numbers. Please try again"
137
+ end
138
+ end
139
+ element_to_be_inserted_at = args[:from] < args[:to] ? args[:to]+1 : args[:to]
140
+ element_to_be_removed = args[:from] < args[:to] ? args[:from] : args[:from]+1
141
+ current_pipe_command_types.insert(element_to_be_inserted_at, current_pipe_command_types.at(args[:from]))
142
+ current_pipe_command_types.delete_at(element_to_be_removed)
143
+ end
144
+
145
+
146
+ # Remove a command that will be piped to the yql query
147
+ def remove_pipe_command(command)
148
+ current_pipe_command_types.delete(command)
149
+ end
150
+
151
+ private
152
+
153
+ def pipe_commands
154
+ return if current_pipe_command_types.empty?
155
+ '| ' + current_pipe_command_types.map{|c| self.send(c)}.join(' | ')
156
+ end
157
+
158
+ def build_select_query
159
+ [select_statement, conditions, limit, pipe_commands].compact.join(' ')
160
+ end
161
+
162
+ def construct_query
163
+ return build_select_query unless @use
164
+ return [@use, build_select_query].join('; ')
165
+ end
166
+
167
+ def select_statement
168
+ select = "select #{column_select} from #{table}"
169
+ return select unless per_page
170
+ with_pagination(select)
171
+ end
172
+
173
+ def with_pagination(select)
174
+ self.current_page ||= 1
175
+ offset = (current_page - 1) * per_page
176
+ last_record = current_page * per_page
177
+ "#{select}(#{offset},#{last_record})"
178
+ end
179
+
180
+ def column_select
181
+ @select ? @select : '*'
182
+ end
183
+
184
+ end
185
+
186
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yql
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Nasir Jamal
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-20 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Yql is a ruby wrapper for Yahoo Query Language.
22
+ email: nas35_in@yahoo.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.rdoc
29
+ files:
30
+ - History.txt
31
+ - Manifest.txt
32
+ - README.rdoc
33
+ - lib/yql.rb
34
+ - lib/yql/client.rb
35
+ - lib/yql/error.rb
36
+ - lib/yql/query_builder.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/nas/yql
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --charset=UTF-8
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ segments:
51
+ - 1
52
+ - 8
53
+ version: "1.8"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.6
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Yql is a ruby wrapper for Yahoo Query Language.
68
+ test_files: []
69
+