Class: Jpzip::Client
- Inherits:
-
Object
- Object
- Jpzip::Client
- Defined in:
- lib/jpzip/client.rb
Overview
Client is the jpzip SDK entry point. Construct it once and reuse it across threads — it is safe for concurrent use.
Instance Method Summary collapse
-
#initialize(base_url: DEFAULT_BASE_URL, cache: nil, memory_cache_size: MemoryLRU::DEFAULT_CAPACITY, on_spec_mismatch: nil, http_client: nil) ⇒ Client
constructor
A new instance of Client.
-
#lookup(zipcode) ⇒ Object
Lookup returns the ZipcodeEntry for
zipcodeor nil if not found. -
#lookup_all ⇒ Object
LookupAll fans out across /g/0..9.json in parallel and merges.
-
#lookup_group(prefix) ⇒ Hash{String => Jpzip::ZipcodeEntry}
LookupGroup fetches all entries under a 1-, 2-, or 3-digit prefix.
- #memory_cache_size ⇒ Object private
-
#meta ⇒ Object
Meta returns the cached /meta.json.
-
#preload(scope) ⇒ Object
Preload pulls the requested scope into L1 (and L2 when configured).
-
#refresh ⇒ Object
Refresh wipes L1 (and L2 when configured) and forgets cached meta.
Constructor Details
#initialize(base_url: DEFAULT_BASE_URL, cache: nil, memory_cache_size: MemoryLRU::DEFAULT_CAPACITY, on_spec_mismatch: nil, http_client: nil) ⇒ Client
Returns a new instance of Client.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/jpzip/client.rb', line 29 def initialize(base_url: DEFAULT_BASE_URL, cache: nil, memory_cache_size: MemoryLRU::DEFAULT_CAPACITY, on_spec_mismatch: nil, http_client: nil) @base_url = base_url.to_s.sub(%r{/+\z}, "") @cache = cache @mem = MemoryLRU.new(memory_cache_size) @on_spec_mismatch = on_spec_mismatch @http_client = http_client @meta_mu = Monitor.new @meta_cached = nil @meta_resolved = false @known_version = nil end |
Instance Method Details
#lookup(zipcode) ⇒ Object
Lookup returns the ZipcodeEntry for zipcode or nil if not found. Malformed input returns nil without contacting the network.
47 48 49 50 51 52 53 54 |
# File 'lib/jpzip/client.rb', line 47 def lookup(zipcode) return nil unless ZIP_REGEX.match?(zipcode.to_s) dict = fetch_prefix_dict(zipcode[0, 3]) return nil if dict.nil? dict[zipcode] end |
#lookup_all ⇒ Object
LookupAll fans out across /g/0..9.json in parallel and merges. The CDN does not publish a single /all.json because the combined file exceeds Cloudflare Pages’ 25 MiB per-file limit.
77 78 79 |
# File 'lib/jpzip/client.rb', line 77 def lookup_all parallel_merge(0.upto(9).map(&:to_s)) { |p1| fetch_url(group_url(p1)) } end |
#lookup_group(prefix) ⇒ Hash{String => Jpzip::ZipcodeEntry}
LookupGroup fetches all entries under a 1-, 2-, or 3-digit prefix. A 2-digit prefix fans out into 10 parallel prefix-3 fetches.
60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/jpzip/client.rb', line 60 def lookup_group(prefix) prefix = prefix.to_s raise InvalidPrefixError, "jpzip: prefix must be 1-3 digits, got #{prefix.inspect}" unless PREFIX_REGEX.match?(prefix) case prefix.length when 3 fetch_prefix_dict(prefix) || {} when 1 fetch_url(group_url(prefix)) || {} when 2 parallel_merge(0.upto(9).map { |i| "#{prefix}#{i}" }) { |p3| fetch_prefix_dict(p3) } end end |
#memory_cache_size ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
151 152 153 |
# File 'lib/jpzip/client.rb', line 151 def memory_cache_size @mem.size end |
#meta ⇒ Object
Meta returns the cached /meta.json. First call hits the network; later calls return the cached value until #refresh is invoked.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/jpzip/client.rb', line 83 def @meta_mu.synchronize do return @meta_cached if @meta_resolved end result = Http.get("#{@base_url}/meta.json", http_client: @http_client) @meta_mu.synchronize do if result.status == 404 @meta_resolved = true @meta_cached = nil return nil end parsed = JSON.parse(result.body) m = Meta.from_hash(parsed) if m.spec_version != SPEC_VERSION && @on_spec_mismatch @on_spec_mismatch.call(SPEC_VERSION, m.spec_version) end if @known_version && @known_version != m.version @mem.clear @cache&.clear end @known_version = m.version @meta_cached = m @meta_resolved = true m end end |
#preload(scope) ⇒ Object
Preload pulls the requested scope into L1 (and L2 when configured). scope is either the string “all” or a 1-3 digit prefix.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/jpzip/client.rb', line 118 def preload(scope) scope = scope.to_s if scope == "all" dict = lookup_all buckets = Hash.new { |h, k| h[k] = {} } dict.each { |zip, entry| buckets[zip[0, 3]][zip] = entry } buckets.each do |p, b| url = prefix_url(p) @mem.set(url, b) write_l2(url, b) end return nil end raise InvalidPrefixError, "jpzip: prefix must be 1-3 digits, got #{scope.inspect}" unless PREFIX_REGEX.match?(scope) lookup_group(scope) nil end |
#refresh ⇒ Object
Refresh wipes L1 (and L2 when configured) and forgets cached meta.
139 140 141 142 143 144 145 146 147 148 |
# File 'lib/jpzip/client.rb', line 139 def refresh @mem.clear @meta_mu.synchronize do @meta_cached = nil @meta_resolved = false @known_version = nil end @cache&.clear nil end |