tlaw 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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +11 -0
- data/.yardopts +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +438 -0
- data/examples/demo_base.rb +10 -0
- data/examples/forecast_io.rb +113 -0
- data/examples/forecast_io_demo.rb +72 -0
- data/examples/open_weather_map.rb +266 -0
- data/examples/open_weather_map_demo.rb +219 -0
- data/examples/tmdb_demo.rb +133 -0
- data/examples/urbandictionary_demo.rb +105 -0
- data/lib/tlaw.rb +67 -0
- data/lib/tlaw/api.rb +58 -0
- data/lib/tlaw/api_path.rb +137 -0
- data/lib/tlaw/data_table.rb +116 -0
- data/lib/tlaw/dsl.rb +511 -0
- data/lib/tlaw/endpoint.rb +132 -0
- data/lib/tlaw/namespace.rb +159 -0
- data/lib/tlaw/param.rb +155 -0
- data/lib/tlaw/param/type.rb +113 -0
- data/lib/tlaw/param_set.rb +111 -0
- data/lib/tlaw/response_processor.rb +124 -0
- data/lib/tlaw/util.rb +45 -0
- data/lib/tlaw/version.rb +7 -0
- data/tlaw.gemspec +53 -0
- metadata +265 -0
@@ -0,0 +1,219 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative 'demo_base'
|
3
|
+
require_relative 'open_weather_map'
|
4
|
+
|
5
|
+
# This is demonstration of TLAW (The Last API Wrapper) library's behavior
|
6
|
+
# and opinions.
|
7
|
+
#
|
8
|
+
# All of below functionality is created by this API wrapper definition:
|
9
|
+
# TODO URL
|
10
|
+
|
11
|
+
# OK, first thing is: all API wrappers created with TLAW, are
|
12
|
+
# _discoverable_ by design. In fact, you can understand all you need to
|
13
|
+
# use the API just from IRB, no need to go to rdoc.info, dig in code,
|
14
|
+
# or, my favourite thing, "see arguments explanation at original API
|
15
|
+
# site".
|
16
|
+
|
17
|
+
# Let's see:
|
18
|
+
|
19
|
+
p TLAW::Examples::OpenWeatherMap
|
20
|
+
# => #<TLAW::Examples::OpenWeatherMap: call-sequence: TLAW::Examples::OpenWeatherMap.new(appid:, lang: "en", units: :standard); namespaces: current, find, forecast; docs: .describe>
|
21
|
+
|
22
|
+
# Let's try this .describe thing which inspect recommends:
|
23
|
+
|
24
|
+
p TLAW::Examples::OpenWeatherMap.describe
|
25
|
+
# TLAW::Examples::OpenWeatherMap.new(appid:, lang: "en", units: :standard)
|
26
|
+
# API for [OpenWeatherMap](http://openweathermap.org/). Only parts
|
27
|
+
# available for free are implemented (as only them could be tested).
|
28
|
+
#
|
29
|
+
# See full docs at http://openweathermap.org/api
|
30
|
+
#
|
31
|
+
# @param appid You need to receive it at http://openweathermap.org/appid (free)
|
32
|
+
# @param lang Language of API responses (affects weather description only).
|
33
|
+
# See http://openweathermap.org/current#multi for list of supported languages. (default = "en")
|
34
|
+
# @param units Units for temperature and other values. Standard is Kelvin.
|
35
|
+
# Possible values: :standard, :metric, :imperial (default = :standard)
|
36
|
+
#
|
37
|
+
# Namespaces:
|
38
|
+
#
|
39
|
+
# .current()
|
40
|
+
# Allows to obtain current weather at one place, designated
|
41
|
+
# by city, location or zip code.
|
42
|
+
#
|
43
|
+
# .find()
|
44
|
+
# Allows to find some place (and weather in it) by set of input
|
45
|
+
# parameters.
|
46
|
+
#
|
47
|
+
# .forecast()
|
48
|
+
# Allows to obtain weather forecast for 5 days with 3-hour
|
49
|
+
# frequency.
|
50
|
+
|
51
|
+
# Note that this multiline output is produced by `p`! So, in IRB/pry
|
52
|
+
# session it would be exactly the same: you just say "something.describe",
|
53
|
+
# and it is just printed the most convenient way.
|
54
|
+
|
55
|
+
# Let's look closer to some of those namespaces:
|
56
|
+
p TLAW::Examples::OpenWeatherMap.namespaces[:current]
|
57
|
+
# => #<TLAW::Examples::OpenWeatherMap::Current: call-sequence: current(); endpoints: city, city_id, location, zip, group; docs: .describe>
|
58
|
+
|
59
|
+
# .describe, anyone?
|
60
|
+
p TLAW::Examples::OpenWeatherMap.namespaces[:current].describe
|
61
|
+
# .current()
|
62
|
+
# Allows to obtain current weather at one place, designated
|
63
|
+
# by city, location or zip code.
|
64
|
+
#
|
65
|
+
# Docs: http://openweathermap.org/current
|
66
|
+
#
|
67
|
+
#
|
68
|
+
# Endpoints:
|
69
|
+
#
|
70
|
+
# .city(city, country_code=nil)
|
71
|
+
# Current weather by city name (with optional country code
|
72
|
+
# specification).
|
73
|
+
#
|
74
|
+
# .city_id(city_id)
|
75
|
+
# Current weather by city id. Recommended by OpenWeatherMap
|
76
|
+
# docs.
|
77
|
+
#
|
78
|
+
# .location(lat, lng)
|
79
|
+
# Current weather by geographic coordinates.
|
80
|
+
#
|
81
|
+
# .zip(zip, country_code=nil)
|
82
|
+
# Current weather by ZIP code (with optional country code
|
83
|
+
# specification).
|
84
|
+
#
|
85
|
+
# .group(city_ids)
|
86
|
+
# Current weather in several cities by their ids.
|
87
|
+
|
88
|
+
# And further:
|
89
|
+
p TLAW::Examples::OpenWeatherMap
|
90
|
+
.namespaces[:current].endpoints[:city]
|
91
|
+
# => #<TLAW::Examples::OpenWeatherMap::Current::City: call-sequence: city(city, country_code=nil); docs: .describe>
|
92
|
+
|
93
|
+
p TLAW::Examples::OpenWeatherMap
|
94
|
+
.namespaces[:current].endpoints[:city].describe
|
95
|
+
# .city(city, country_code=nil)
|
96
|
+
# Current weather by city name (with optional country code
|
97
|
+
# specification).
|
98
|
+
#
|
99
|
+
# Docs: http://openweathermap.org/current#name
|
100
|
+
#
|
101
|
+
# @param city City name
|
102
|
+
# @param country_code ISO 3166 2-letter country code
|
103
|
+
|
104
|
+
# Note, that all above classes and methods are generated at moment of
|
105
|
+
# API definition, so there is no cumbersome dispatching at runtime:
|
106
|
+
|
107
|
+
p TLAW::Examples::OpenWeatherMap.instance_methods(false)
|
108
|
+
# => [:current, :find, :forecast]
|
109
|
+
p TLAW::Examples::OpenWeatherMap::Current.instance_methods(false)
|
110
|
+
# => [:city, :city_id, :location, :zip, :group]
|
111
|
+
p TLAW::Examples::OpenWeatherMap::Current.instance_method(:city).parameters
|
112
|
+
# => [[:req, :city], [:opt, :country_code]]
|
113
|
+
|
114
|
+
# E.g. namespace is a class, providing methods for all the child
|
115
|
+
# namespaces and endpoints! And all params are just method params.
|
116
|
+
|
117
|
+
# OK, let's go for some real things, not just documentation reading.
|
118
|
+
|
119
|
+
# You need to create key here: http://openweathermap.org/appid
|
120
|
+
# And run the script this way:
|
121
|
+
#
|
122
|
+
# OPEN_WEATHER_MAP={your_id} examples/open_weather_map_demo.rb
|
123
|
+
#
|
124
|
+
weather = TLAW::Examples::OpenWeatherMap
|
125
|
+
.new(appid: ENV['OPEN_WEATHER_MAP'], units: :metric)
|
126
|
+
p weather
|
127
|
+
# => #<TLAW::Examples::OpenWeatherMap.new(appid: {your id}, lang: nil, units: :metric) namespaces: current, find, forecast; docs: .describe>
|
128
|
+
|
129
|
+
# Looks familiar and nothing new.
|
130
|
+
|
131
|
+
p weather.current
|
132
|
+
# => #<current() endpoints: city, city_id, location, zip, group; docs: .describe>
|
133
|
+
|
134
|
+
# Saem.
|
135
|
+
|
136
|
+
pp weather.current.city('Kharkiv')
|
137
|
+
# {"weather.id"=>800,
|
138
|
+
# "weather.main"=>"Clear",
|
139
|
+
# "weather.description"=>"clear sky",
|
140
|
+
# "weather.icon"=>"http://openweathermap.org/img/w/01n.png",
|
141
|
+
# "base"=>"cmc stations",
|
142
|
+
# "main.temp"=>23,
|
143
|
+
# "main.pressure"=>1013,
|
144
|
+
# "main.humidity"=>40,
|
145
|
+
# "main.temp_min"=>23,
|
146
|
+
# "main.temp_max"=>23,
|
147
|
+
# "wind.speed"=>2,
|
148
|
+
# "wind.deg"=>190,
|
149
|
+
# "clouds.all"=>0,
|
150
|
+
# "dt"=>2016-09-05 20:30:00 +0300,
|
151
|
+
# "sys.type"=>1,
|
152
|
+
# "sys.id"=>7355,
|
153
|
+
# "sys.message"=>0.0115,
|
154
|
+
# "sys.country"=>"UA",
|
155
|
+
# "sys.sunrise"=>2016-09-05 05:57:26 +0300,
|
156
|
+
# "sys.sunset"=>2016-09-05 19:08:13 +0300,
|
157
|
+
# "id"=>706483,
|
158
|
+
# "name"=>"Kharkiv",
|
159
|
+
# "cod"=>200,
|
160
|
+
# "coord"=>#<Geo::Coord 50.000000,36.250000>}
|
161
|
+
|
162
|
+
# Whoa!
|
163
|
+
#
|
164
|
+
# What we see here (except for "OK, it works")?
|
165
|
+
#
|
166
|
+
# Several pretty improtant things:
|
167
|
+
#
|
168
|
+
# * TLAW response processing is _highly opinionated_. It tends do flatten
|
169
|
+
# all the hashes: original has something like
|
170
|
+
# {weather: {...}, main: {...}, sys: {...}
|
171
|
+
# * It is done, again, for the sake of _discoverability_. You, like, see
|
172
|
+
# at once all things API response proposes; you can do `response.keys`
|
173
|
+
# to understand what you got instead of `response.keys`, hm,
|
174
|
+
# `response['weather'].class`, ah, ok, `response['weather'].keys` and
|
175
|
+
# so on;
|
176
|
+
# * TLAW allows easy postprocessing of response: our example API parses
|
177
|
+
# timestamps into proper ruby times, and (just to promote related gem),
|
178
|
+
# converts "coord.lat" and "coord.lng" to one instance of a Geo::Coord,
|
179
|
+
# from https://github.com/zverok/geo_coord
|
180
|
+
#
|
181
|
+
|
182
|
+
# Finally, one HUGE design decision related to "opinionated response
|
183
|
+
# processing":
|
184
|
+
pp weather.forecast.city('Kharkiv')
|
185
|
+
# {"city.id"=>706483,
|
186
|
+
# "city.name"=>"Kharkiv",
|
187
|
+
# "city.country"=>"UA",
|
188
|
+
# "city.population"=>0,
|
189
|
+
# "city.sys.population"=>0,
|
190
|
+
# "cod"=>"200",
|
191
|
+
# "message"=>0.0276,
|
192
|
+
# "cnt"=>40,
|
193
|
+
# "list"=>
|
194
|
+
# #<TLAW::DataTable[dt, main.temp, main.temp_min, main.temp_max, main.pressure, main.sea_level, main.grnd_level, main.humidity, main.temp_kf, weather.id, weather.main, weather.description, weather.icon, clouds.all, wind.speed, wind.deg, sys.pod] x 40>,
|
195
|
+
# "city.coord"=>#<Geo::Coord 50.000000,36.250000>}
|
196
|
+
|
197
|
+
# Hmm? What is this DataTable thingy? It is (loosy) implementation of
|
198
|
+
# DataFrame data type. You can think of it as an array of homogenous
|
199
|
+
# hashes -- which could be considered the main type of useful JSON API
|
200
|
+
# data.
|
201
|
+
forecasts = weather.forecast.city('Kharkiv')['list']
|
202
|
+
|
203
|
+
p forecasts.count
|
204
|
+
# => 40
|
205
|
+
p forecasts.keys
|
206
|
+
# => ["dt", "main.temp", "main.temp_min", "main.temp_max", "main.pressure", "main.sea_level", "main.grnd_level", "main.humidity", "main.temp_kf", "weather.id", "weather.main", "weather.description", "weather.icon", "clouds.all", "wind.speed", "wind.deg", "sys.pod"]
|
207
|
+
p forecasts.first
|
208
|
+
# => {"dt"=>2016-09-06 00:00:00 +0300, "main.temp"=>12.67, "main.temp_min"=>12.67, "main.temp_max"=>15.84, "main.pressure"=>1006.67, "main.sea_level"=>1026.62, "main.grnd_level"=>1006.67, "main.humidity"=>74, "main.temp_kf"=>-3.17, "weather.id"=>800, "weather.main"=>"Clear", "weather.description"=>"clear sky", "weather.icon"=>"http://openweathermap.org/img/w/01n.png", "clouds.all"=>0, "wind.speed"=>1.26, "wind.deg"=>218.509, "sys.pod"=>"n"}
|
209
|
+
|
210
|
+
p forecasts['dt'].first(3)
|
211
|
+
# => [2016-09-06 00:00:00 +0300, 2016-09-06 03:00:00 +0300, 2016-09-06 06:00:00 +0300]
|
212
|
+
|
213
|
+
p forecasts.columns('dt', 'main.temp').to_a.first(3)
|
214
|
+
# => [{"dt"=>2016-09-06 00:00:00 +0300, "main.temp"=>12.67}, {"dt"=>2016-09-06 03:00:00 +0300, "main.temp"=>11.65}, {"dt"=>2016-09-06 06:00:00 +0300, "main.temp"=>12.41}]
|
215
|
+
|
216
|
+
# All of it works and you can check it by yourself.
|
217
|
+
#
|
218
|
+
# Again, EVERYTHING you can see in this example is created by short and
|
219
|
+
# focused API definition: TODO URL
|
@@ -0,0 +1,133 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative 'demo_base'
|
3
|
+
|
4
|
+
# This example demonstrates how TLAW allows you to define and redefine
|
5
|
+
# API wrappers on the fly—to the extent you need and without much
|
6
|
+
# bothering—and still have all the goodies.
|
7
|
+
|
8
|
+
# For example, you have pretty large and complicated TheMoviesDatabase API:
|
9
|
+
# http://docs.themoviedb.apiary.io/
|
10
|
+
# ...and all you want is just to search for movies and get their posters.
|
11
|
+
# All existing TMDB Ruby wrappers (I know at least three) are strange.
|
12
|
+
#
|
13
|
+
# What you'll do?
|
14
|
+
#
|
15
|
+
# That's what:
|
16
|
+
|
17
|
+
class TMDB < TLAW::API
|
18
|
+
define do
|
19
|
+
base 'http://api.themoviedb.org/3'
|
20
|
+
param :api_key, required: true
|
21
|
+
param :language, default: 'en'
|
22
|
+
|
23
|
+
namespace :movies, '/movie' do
|
24
|
+
namespace :[], '/{id}' do
|
25
|
+
param :id, required: true
|
26
|
+
|
27
|
+
endpoint :images
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
namespace :search do
|
32
|
+
endpoint :movie do
|
33
|
+
param :query, required: true, keyword: false
|
34
|
+
|
35
|
+
post_process_items('results') {
|
36
|
+
post_process 'release_date', &Date.method(:parse)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# You need to run it like TMDB={your_key} ./examples/tmdb_demo.rb
|
44
|
+
tmdb = TMDB.new(api_key: ENV['TMDB'])
|
45
|
+
|
46
|
+
pp tmdb.search.movie('guardians of the galaxy')
|
47
|
+
# {"page"=>1,
|
48
|
+
# "results"=>
|
49
|
+
# #<TLAW::DataTable[poster_path, adult, overview, release_date, genre_ids, id, original_title, original_language, title, backdrop_path, popularity, vote_count, video, vote_average] x 2>,
|
50
|
+
# "total_results"=>2,
|
51
|
+
# "total_pages"=>1}
|
52
|
+
|
53
|
+
pp tmdb.search.movie('guardians of the galaxy')['results'].first
|
54
|
+
# {"poster_path"=>"/y31QB9kn3XSudA15tV7UWQ9XLuW.jpg",
|
55
|
+
# "adult"=>false,
|
56
|
+
# "overview"=>
|
57
|
+
# "Light years from Earth, 26 years after being abducted, Peter Quill finds himself the prime target of a manhunt after discovering an orb wanted by Ronan the Accuser.",
|
58
|
+
# "release_date"=>#<Date: 2014-07-30 ((2456869j,0s,0n),+0s,2299161j)>,
|
59
|
+
# "genre_ids"=>[28, 878, 12],
|
60
|
+
# "id"=>118340,
|
61
|
+
# "original_title"=>"Guardians of the Galaxy",
|
62
|
+
# "original_language"=>"en",
|
63
|
+
# "title"=>"Guardians of the Galaxy",
|
64
|
+
# "backdrop_path"=>"/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg",
|
65
|
+
# "popularity"=>12.287455,
|
66
|
+
# "vote_count"=>5067,
|
67
|
+
# "video"=>false,
|
68
|
+
# "vote_average"=>7.96}
|
69
|
+
|
70
|
+
# OK, now we have an id
|
71
|
+
pp tmdb.movies[118340].images
|
72
|
+
|
73
|
+
# Note, that [] is also namespace accessor here :) With param. See API
|
74
|
+
# description above.
|
75
|
+
|
76
|
+
pp tmdb.movies[118340].images['posters'].last
|
77
|
+
# {"aspect_ratio"=>0.666666666666667,
|
78
|
+
# "file_path"=>"/6YUodKKkqIIDx6Hk7ZkaVOxnWND.jpg",
|
79
|
+
# "height"=>1500,
|
80
|
+
# "iso_639_1"=>"ru",
|
81
|
+
# "vote_average"=>0.0,
|
82
|
+
# "vote_count"=>0,
|
83
|
+
# "width"=>1000}
|
84
|
+
|
85
|
+
# Hmm, maybe we need some path post-processing?.. How about adding it
|
86
|
+
# right now? Assuming our API is already described by someone else...
|
87
|
+
tmdb.class.define do
|
88
|
+
namespace :movies do
|
89
|
+
namespace :[] do
|
90
|
+
endpoint :images do
|
91
|
+
post_process_items 'posters' do
|
92
|
+
post_process('file_path') { |p| 'https://image.tmdb.org/t/p/original' + p }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
pp tmdb.movies[118340].images['posters'].last
|
100
|
+
# Ah, much better!
|
101
|
+
#
|
102
|
+
# {"aspect_ratio"=>0.666666666666667,
|
103
|
+
# "file_path"=>
|
104
|
+
# "https://image.tmdb.org/t/p/original/6YUodKKkqIIDx6Hk7ZkaVOxnWND.jpg",
|
105
|
+
# "height"=>1500,
|
106
|
+
# "iso_639_1"=>"ru",
|
107
|
+
# "vote_average"=>0.0,
|
108
|
+
# "vote_count"=>0,
|
109
|
+
# "width"=>1000}
|
110
|
+
|
111
|
+
|
112
|
+
# Note, that despite not adding a bit of documentation, you still have
|
113
|
+
# your API wrapper discoverable:
|
114
|
+
p TMDB
|
115
|
+
# #<TMDB: call-sequence: TMDB.new(api_key:, language: "en"); namespaces: movies, search; docs: .describe>
|
116
|
+
p tmdb.movies.describe
|
117
|
+
# .movies()
|
118
|
+
#
|
119
|
+
#
|
120
|
+
# Namespaces:
|
121
|
+
#
|
122
|
+
# .[](id)
|
123
|
+
|
124
|
+
p tmdb.movies.namespaces[:[]].describe
|
125
|
+
# .[](id)
|
126
|
+
# @param id
|
127
|
+
#
|
128
|
+
# Endpoints:
|
129
|
+
#
|
130
|
+
# .images()
|
131
|
+
|
132
|
+
# So, you can still investigate, navigate and get meaningful API errors
|
133
|
+
# with backtraces... While you spent only like 15 lines on API description.
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative 'demo_base'
|
3
|
+
|
4
|
+
# That's an example of TLAW's strength.
|
5
|
+
#
|
6
|
+
# Urbandictionary API is really small (just two endpoints, only one of
|
7
|
+
# which is actually useful, because /random is more like a joke).
|
8
|
+
#
|
9
|
+
# But you still need to remember the protocol, parse the answer and so
|
10
|
+
# on.
|
11
|
+
#
|
12
|
+
# There is even separate gem: https://github.com/ryangreenberg/urban_dictionary
|
13
|
+
# Its `lib` folder contains 7 files, 9 classes/modules and 300 lines of
|
14
|
+
# code, I kid you not.
|
15
|
+
#
|
16
|
+
# I have no intention to offend that gem's author! I just saying that's
|
17
|
+
# what you get when you need to design everything from scratch, like HTTP
|
18
|
+
# client and params processing and response parsing and whatnot.
|
19
|
+
#
|
20
|
+
# Oh, and there is another one: https://github.com/tmiller/urban
|
21
|
+
#
|
22
|
+
# But when somebody really need them (for chatbots), they use neither,
|
23
|
+
# just redefine everything from scratch with rough net connection and
|
24
|
+
# response parsing (because both of aforementioned gems are too thick
|
25
|
+
# wrappers to rely on them):
|
26
|
+
# * https://github.com/jimmycuadra/lita-urban-dictionary
|
27
|
+
# * https://github.com/cinchrb/cinch-urbandictionary
|
28
|
+
#
|
29
|
+
# Here is our version (17 codelines, including namespacing and bit of
|
30
|
+
# docs, API definition itself takes like 7 lines only):
|
31
|
+
#
|
32
|
+
module TLAW
|
33
|
+
module Examples
|
34
|
+
class UrbanDictionary < TLAW::API
|
35
|
+
define do
|
36
|
+
desc %Q{
|
37
|
+
Really small API. Described as "official but undocumented"
|
38
|
+
by some.
|
39
|
+
}
|
40
|
+
|
41
|
+
base 'http://api.urbandictionary.com/v0'
|
42
|
+
|
43
|
+
endpoint :define, '/define?term={term}' do
|
44
|
+
param :term, required: true
|
45
|
+
end
|
46
|
+
|
47
|
+
endpoint :random, '/random'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Usage (response is clear as tears, could be integrated anywhere):
|
54
|
+
|
55
|
+
d = TLAW::Examples::UrbanDictionary.new
|
56
|
+
|
57
|
+
p d.describe
|
58
|
+
# TLAW::Examples::UrbanDictionary.new()
|
59
|
+
# Really small API. Described as "official but undocumented"
|
60
|
+
# by some.
|
61
|
+
#
|
62
|
+
# Endpoints:
|
63
|
+
#
|
64
|
+
# .define(term)
|
65
|
+
#
|
66
|
+
# .random()
|
67
|
+
|
68
|
+
res = d.define('trollface')
|
69
|
+
|
70
|
+
pp res
|
71
|
+
# {"tags"=>
|
72
|
+
# ["troll",
|
73
|
+
# "trolling",
|
74
|
+
# "meme",
|
75
|
+
# "4chan",
|
76
|
+
# "troll face",
|
77
|
+
# "coolface",
|
78
|
+
# "trollfacing",
|
79
|
+
# "trolls",
|
80
|
+
# "backpfeifengesicht",
|
81
|
+
# "derp"],
|
82
|
+
# "result_type"=>"exact",
|
83
|
+
# "list"=>
|
84
|
+
# #<TLAW::DataTable[definition, permalink, thumbs_up, author, word, defid, current_vote, example, thumbs_down] x 7>,
|
85
|
+
# "sounds"=>[]}
|
86
|
+
|
87
|
+
pp res['list'].columns('word', 'thumbs_up', 'thumbs_down').to_a
|
88
|
+
# [{"word"=>"Trollface", "thumbs_up"=>418, "thumbs_down"=>99},
|
89
|
+
# {"word"=>"Troll Face", "thumbs_up"=>481, "thumbs_down"=>318},
|
90
|
+
# {"word"=>"Troll Face", "thumbs_up"=>340, "thumbs_down"=>184},
|
91
|
+
# {"word"=>"trollface", "thumbs_up"=>115, "thumbs_down"=>35},
|
92
|
+
# {"word"=>"trollface", "thumbs_up"=>94, "thumbs_down"=>30},
|
93
|
+
# {"word"=>"trollface", "thumbs_up"=>61, "thumbs_down"=>54},
|
94
|
+
# {"word"=>"Troll Face", "thumbs_up"=>81, "thumbs_down"=>181}]
|
95
|
+
|
96
|
+
pp d.random['list'].columns('word', 'example').first(3).to_a
|
97
|
+
# [{"word"=>"pH", "example"=>"Get that ph out of the shower.\r\n\r\n "},
|
98
|
+
# {"word"=>"spocking",
|
99
|
+
# "example"=>
|
100
|
+
# "The dirty bitch couldn’t get enough so I gave her a damn good spocking"},
|
101
|
+
# {"word"=>"mormon",
|
102
|
+
# "example"=>
|
103
|
+
# "Oh my gosh are the Smiths mormons?! We better have a party so they can bring some frickin' sweet green jello!..."}]
|
104
|
+
|
105
|
+
# That's it ¯\_(ツ)_/¯
|