powo_ruby
powo_ruby is a small, defensive, unofficial Ruby client for the Plants of the World Online (POWO) API.
Disclaimer
- This gem is not an official Kew product.
- POWO's API is undocumented and may change or break at any time.
- The API is publicly accessible and does not require authentication, but you should use it responsibly.
Attribution: Data and service provided by the Royal Botanic Gardens, Kew (POWO: Plants of the World Online).
Installation
Add to your Gemfile:
gem "powo_ruby"Then:
bundle installOr install directly:
gem install powo_rubyUsage
Convenience clients (recommended)
This gem exposes two convenience client constructors:
-
PowoRuby.powo(POWO allow-list + POWO group keys) -
PowoRuby.ipni(IPNI allow-list + IPNI group keys)
Both return a configured PowoRuby::Client instance (memoized per-thread unless you pass overrides).
Basic search (POWO)
require "powo_ruby"
response = PowoRuby.powo.search.query(
query: "Apocynaceae",
filters: {
family: "Apocynaceae",
accepted: true
}
)
response.total_count #=> Integer or nil
response.results #=> Array of result hashesLookup by POWO/IPNI identifier
taxon = PowoRuby.powo.taxa.lookup("urn:lsid:ipni.org:names:30000618-2")
taxon.raw #=> Hash (schema may change)Advanced search (structured)
advanced_search only accepts parameters defined in docs/POWO_SEARCH_TERMS.md.
Flat form:
response = PowoRuby.powo.search.advanced(
family: "Fabaceae",
accepted: true,
limit: 24
)Grouped form:
response = PowoRuby.powo.search.advanced(
name: { family: "Fabaceae", genus: "Acacia" },
geography: { country: "Brazil" },
accepted: true
)Pagination (Enumerator-based)
POWO uses a cursor for paging. For most use-cases, prefer the *_each enumerators.
PowoRuby.powo.search.each(query: "Acacia", filters: { accepted: true }).take(50)Or for advanced search:
enum = PowoRuby.powo.search.advanced_each(name: { family: "Fabaceae" }, accepted: true)
enum.each do |row|
puts row["name"]
endIPNI mode
IPNI is exposed at the same level as POWO, and validates parameters against the IPNI term list found in docs/POWO_SEARCH_TERMS.md:
response = PowoRuby.ipni.search.query(query: "Poa annua", filters: { family: "Poaceae" })Note: POWO's API does not expose a clearly documented /ipni/... endpoint under /api/2. This gem therefore uses the same /search and /taxon/<id> endpoints but validates parameters against the IPNI allow-list.
Configuration
PowoRuby.configure do |c|
c.base_url = "https://powo.science.kew.org/api/2"
c.timeout = 10
c.open_timeout = 5
c.retries = true
endLogger support
Pass any logger responding to warn:
require "logger"
PowoRuby.configure do |c|
c.logger = Logger.new($stdout)
endCaching support (optional adapter)
Provide an object that responds to fetch(key, options = nil) { ... }:
cache = {}
adapter = Object.new
def adapter.fetch(key)
@store ||= {}
return @store[key] if @store.key?(key)
@store[key] = yield
end
PowoRuby.configure do |c|
c.cache = adapter
endYou can also pass cache options (e.g. TTL) and a namespace for cache keys:
PowoRuby.configure do |c|
c.cache = Rails.cache
c.cache_options = { expires_in: 60 } # seconds
c.cache_namespace = "my_app"
endCLI (optional)
After installation:
powo_ruby search "Acacia" --filter accepted=true --filter family=Fabaceae
powo_ruby lookup "urn:lsid:ipni.org:names:30000618-2"
powo_ruby ipni-search "Poa annua" --filter family=PoaceaeDevelopment
bin/setup
bundle exec rspec
bundle exec rubocopExamples
Examples (including a tiny Sinatra app with basic views for search + taxon lookup) live in the separate repo rekapap/powo_ruby_examples.
git clone https://github.com/rekapap/powo_ruby_examples.git
cd powo_ruby_examples/basic_app
bundle install
bundle exec rackupLicense
MIT. See LICENSE.txt.