lib/beerdb/reader.rb in beerdb-0.1.0 vs lib/beerdb/reader.rb in beerdb-0.2.0

- old
+ new

@@ -66,10 +66,13 @@ def load( name ) if name =~ /\/([a-z]{2})\/beers/ ## auto-add required country code (from folder structure) load_beers( $1, name ) + elsif name =~ /\/([a-z]{2})\/breweries/ + ## auto-add required country code (from folder structure) + load_breweries( $1, name ) else logger.error "unknown beer.db fixture type >#{name}<" # todo/fix: exit w/ error end end @@ -84,36 +87,173 @@ path = "#{include_path}/#{name}.txt" logger.info "parsing data '#{name}' (#{path})..." reader = ValuesReader.new( path, more_values ) - + load_beers_worker( reader ) Prop.create_from_fixture!( name, path ) end + def load_breweries( country_key, name, more_values={} ) + country = Country.find_by_key!( country_key ) + logger.debug "Country #{country.key} >#{country.title} (#{country.code})<" + + more_values[ :country_id ] = country.id + + path = "#{include_path}/#{name}.txt" + + logger.info "parsing data '#{name}' (#{path})..." + + reader = ValuesReader.new( path, more_values ) + + load_breweries_worker( reader ) + + Prop.create_from_fixture!( name, path ) + end + + private + def load_breweries_worker( reader ) + ## NB: assumes active activerecord db connection + + reader.each_line do |attribs, values| + + + ### todo/fix: move this code to model (lets us reuse it) + + value_tag_keys = [] + + ### check for "default" tags - that is, if present attribs[:tags] remove from hash + + if attribs[:tags].present? + more_tag_keys = attribs[:tags].split('|') + attribs.delete(:tags) + + ## unify; replace _ w/ space; remove leading n trailing whitespace + more_tag_keys = more_tag_keys.map do |key| + key = key.gsub( '_', ' ' ) + key = key.strip + key + end + + value_tag_keys += more_tag_keys + end + + + ## check for optional values + values.each_with_index do |value,index| + if value =~ /^country:/ ## country: + value_country_key = value[8..-1] ## cut off country: prefix + value_country = Country.find_by_key!( value_country_key ) + attribs[ :country_id ] = value_country.id + elsif value =~ /^region:/ ## region: + value_region_key = value[7..-1] ## cut off region: prefix + value_region = Region.find_by_key_and_country_id!( value_region_key, attribs[:country_id] ) + attribs[ :region_id ] = value_region.id + elsif value =~ /^[A-Z]{1,2}$/ ## assume region code e.g. TX or N + value_region = Region.find_by_key_and_country_id!( value.downcase, attribs[:country_id] ) + attribs[ :region_id ] = value_region.id + elsif value =~ /^city:/ ## city: + value_city_key = value[5..-1] ## cut off city: prefix + value_city = City.find_by_key( value_city_key ) + if value_city.present? + attribs[ :city_id ] = value_city.id + else + ## todo/fix: add strict mode flag - fail w/ exit 1 in strict mode + logger.warn "city with key #{value_city_key} missing" + end + + ## for easy queries: cache region_id (from city) + # - check if city w/ region if yes, use it for brewery too + if value_city.present? && value_city.region.present? + attribs[ :region_id ] = value_city.region.id + end + elsif value =~ /^[0-9]{4}$/ # founded/established year e.g. 1776 + attribs[ :founded ] = value.to_i + elsif value =~ /\/{2}/ # if value includes // assume address e.g. 3970 Weitra // Sparkasseplatz 160 + attribs[ :address ] = value + elsif (values.size==(index+1)) && value =~ /^[a-z0-9\|_ ]+$/ # tags must be last entry + + logger.debug " found tags: >>#{value}<<" + + tag_keys = value.split('|') + + ## unify; replace _ w/ space; remove leading n trailing whitespace + tag_keys = tag_keys.map do |key| + key = key.gsub( '_', ' ' ) + key = key.strip + key + end + + value_tag_keys += tag_keys + else + # issue warning: unknown type for value + logger.warn "unknown type for value >#{value}<" + end + end # each value + + rec = Brewery.find_by_key( attribs[ :key ] ) + + if rec.present? + logger.debug "update Brewery #{rec.id}-#{rec.key}:" + else + logger.debug "create Brewery:" + rec = Brewery.new + end + + logger.debug attribs.to_json + + rec.update_attributes!( attribs ) + + ################## + ## add taggings + + if value_tag_keys.size > 0 + + value_tag_keys.uniq! # remove duplicates + logger.debug " adding #{value_tag_keys.size} taggings: >>#{value_tag_keys.join('|')}<<..." + + ### fix/todo: check tag_ids and only update diff (add/remove ids) + + value_tag_keys.each do |key| + tag = Tag.find_by_key( key ) + if tag.nil? # create tag if it doesn't exit + logger.debug " creating tag >#{key}<" + tag = Tag.create!( key: key ) + end + rec.tags << tag + end + end + + end # each_line + + end # method load_breweries_worker + + def load_beers_worker( reader ) ## NB: assumes active activerecord db connection ## reader.each_line do |attribs, values| + + ### todo/fix: move this code to model (lets us reuse it) value_tag_keys = [] ### check for "default" tags - that is, if present attribs[:tags] remove from hash if attribs[:tags].present? more_tag_keys = attribs[:tags].split('|') attribs.delete(:tags) - ## unify; replace _w/ space; remove leading n trailing whitespace + ## unify; replace _ w/ space; remove leading n trailing whitespace more_tag_keys = more_tag_keys.map do |key| key = key.gsub( '_', ' ' ) key = key.strip key end @@ -126,21 +266,65 @@ values.each_with_index do |value,index| if value =~ /^country:/ ## country: value_country_key = value[8..-1] ## cut off country: prefix value_country = Country.find_by_key!( value_country_key ) attribs[ :country_id ] = value_country.id + elsif value =~ /^region:/ ## region: + value_region_key = value[7..-1] ## cut off region: prefix + value_region = Region.find_by_key_and_country_id!( value_region_key, attribs[:country_id] ) + attribs[ :region_id ] = value_region.id + elsif value =~ /^[A-Z]{1,2}$/ ## assume region code e.g. TX or N + value_region = Region.find_by_key_and_country_id!( value.downcase, attribs[:country_id] ) + attribs[ :region_id ] = value_region.id elsif value =~ /^city:/ ## city: value_city_key = value[5..-1] ## cut off city: prefix - value_city = City.find_by_key!( value_city_key ) - attribs[ :city_id ] = value_city.id + value_city = City.find_by_key( value_city_key ) + if value_city.present? + attribs[ :city_id ] = value_city.id + else + ## todo/fix: add strict mode flag - fail w/ exit 1 in strict mode + logger.warn "city with key #{value_city_key} missing" + end + elsif value =~ /^by:/ ## by: -brewed by/brewery + value_brewery_key = value[3..-1] ## cut off by: prefix + value_brewery = Brewery.find_by_key!( value_brewery_key ) + attribs[ :brewery_id ] = value_brewery.id + + # for easy queries cache city and region ids + + # 1) check if brewery has city - if yes, use it for beer too + if value_brewery.city.present? + attribs[ :city_id ] = value_brewery.city.id + end + + # 2) check if brewery has city w/ region if yes, use it for beer to + # if not check for region for brewery + if value_brewery.city.present? && value_brewery.city.region.present? + attribs[ :region_id ] = value_brewery.city.region.id + elsif value_brewery.region.present? + attribs[ :region_id ] = value_brewery.region.id + end + + elsif value =~ /^<?\s*(\d+(?:\.\d+)?)\s*%$/ ## abv (alcohol by volumee) + ## nb: allow leading < e.g. <0.5% + value_abv_str = $1.dup # convert to decimal? how? use float? + attribs[ :abv ] = value_abv_str + elsif value =~ /^(\d+(?:\.\d+)?)°$/ ## plato (stammwuerze/gravity?) e.g. 11.2° + ## nb: no whitespace allowed between ° and number e.g. 11.2° + value_plato_str = $1.dup # convert to decimal? how? use float? + attribs[ :plato ] = value_plato_str + elsif value =~ /^(\d+(?:\.\d+)?)\s*kcal(?:\/100ml)?$/ ## kcal + ## nb: allow 44.4 kcal/100ml or 44.4 kcal or 44.4kcal + value_kcal_str = $1.dup # convert to decimal? how? use float? + attribs[ :kcal ] = value_kcal_str elsif (values.size==(index+1)) && value =~ /^[a-z0-9\|_ ]+$/ # tags must be last entry logger.debug " found tags: >>#{value}<<" tag_keys = value.split('|') - ## unify; replace _w/ space; remove leading n trailing whitespace + ## unify; replace _ w/ space; remove leading n trailing whitespace tag_keys = tag_keys.map do |key| key = key.gsub( '_', ' ' ) key = key.strip key end @@ -164,11 +348,10 @@ logger.debug attribs.to_json rec.update_attributes!( attribs ) -=begin ################## ## add taggings if value_tag_keys.size > 0 @@ -184,11 +367,10 @@ tag = Tag.create!( key: key ) end rec.tags << tag end end -=end - + end # each_line end # method load_beers_worker end # class Reader