beerdb 0.9.13 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,256 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module BeerDb
4
- module Model
5
-
6
- class Brewery < ActiveRecord::Base
7
-
8
- extend TextUtils::TagHelper # will add self.find_tags, self.find_tags_in_attribs!, etc.
9
-
10
- # NB: use extend - is_<type>? become class methods e.g. self.is_<type>? for use in
11
- # self.create_or_update_from_values
12
- extend TextUtils::ValueHelper # e.g. self.is_year?, self.is_region?, is_address?, is_taglist? etc.
13
- extend TextUtils::AddressHelper # e.g self.normalize_addr, self.find_city_in_addr, etc.
14
-
15
- self.table_name = 'breweries'
16
-
17
- belongs_to :country, :class_name => 'WorldDb::Model::Country', :foreign_key => 'country_id'
18
- belongs_to :region, :class_name => 'WorldDb::Model::Region', :foreign_key => 'region_id'
19
- belongs_to :city, :class_name => 'WorldDb::Model::City', :foreign_key => 'city_id'
20
-
21
- has_many :beers, :class_name => 'BeerDb::Model::Beer', :foreign_key => 'brewery_id'
22
- has_many :brands, :class_name => 'BeerDb::Model::Brand', :foreign_key => 'brand_id'
23
-
24
- has_many :taggings, class_name: 'TagDb::Model::Tagging', :as => :taggable
25
- has_many :tags, class_name: 'TagDb::Model::Tag', :through => :taggings
26
-
27
-
28
- validates :key, :format => { :with => /\A[a-z][a-z0-9]+\z/, :message => 'expected two or more lowercase letters a-z or 0-9 digits' }
29
-
30
-
31
- ### support old names (read-only) for now (remove later ??)
32
-
33
- def founded() since; end
34
- def founded=(value) self.since = value; end
35
-
36
- def opened() since; end
37
- def openend=(value) self.since = value; end
38
-
39
- def m?() prod_m == true; end
40
- def l?() prod_l == true; end
41
-
42
- ## TODO: activerecord supplies brewpub? already? same as attrib; check w/ test case (and remove here)
43
- def brewpub?() brewpub == true; end
44
-
45
-
46
-
47
- def as_json_v2( opts={} )
48
- # NB: do NOT overwrite "default" / builtin as_json, thus, lets use as_json_v2
49
- BrewerySerializer.new( self ).as_json
50
- end
51
-
52
-
53
-
54
- def self.create_or_update_from_values( values, more_attribs={} )
55
- attribs, more_values = find_key_n_title( values )
56
- attribs = attribs.merge( more_attribs )
57
-
58
- # check for optional values
59
- Brewery.create_or_update_from_attribs( attribs, more_values )
60
- end
61
-
62
-
63
- def self.create_or_update_from_attribs( new_attributes, values )
64
-
65
- ## fix: add/configure logger for ActiveRecord!!!
66
- logger = LogKernel::Logger.root
67
-
68
- value_tag_keys = []
69
- value_brands = ''
70
-
71
- ## check for grades (e.g. ***/**/*) in titles (will add new_attributes[:grade] to hash)
72
- ## if grade missing; set default to 4; lets us update overwrite 1,2,3 values on update
73
- new_attributes[ :grade ] ||= 4
74
-
75
- ### check for "default" tags - that is, if present new_attributes[:tags] remove from hash
76
- value_tag_keys += find_tags_in_attribs!( new_attributes )
77
-
78
- ## check for optional values
79
- values.each_with_index do |value,index|
80
- if match_country(value) do |country|
81
- new_attributes[ :country_id ] = country.id
82
- end
83
- elsif match_region_for_country(value,new_attributes[:country_id]) do |region|
84
- new_attributes[ :region_id ] = region.id
85
- end
86
- elsif match_city(value) do |city|
87
- if city.present?
88
- new_attributes[ :city_id ] = city.id
89
- else
90
- ## todo/fix: add strict mode flag - fail w/ exit 1 in strict mode
91
- logger.warn "city with key #{value[5..-1]} missing - for brewery #{new_attributes[:key]}"
92
- end
93
-
94
- ## for easy queries: cache region_id (from city)
95
- # - check if city w/ region if yes, use it for brewery too
96
- if city.present? && city.region.present?
97
- new_attributes[ :region_id ] = city.region.id
98
- end
99
- end
100
- elsif match_year( value ) do |num| # founded/established year e.g. 1776
101
- new_attributes[ :since ] = num
102
- end
103
- elsif match_hl( value ) do |num| # e.g. 20_000 hl or 50hl etc.
104
- new_attributes[ :prod ] = num
105
- end
106
- elsif match_website( value ) do |website| # check for url/internet address e.g. www.ottakringer.at
107
- # fix: support more url format (e.g. w/o www. - look for .com .country code etc.)
108
- new_attributes[ :web ] = website
109
- end
110
- elsif is_address?( value ) # if value includes // assume address e.g. 3970 Weitra // Sparkasseplatz 160
111
- new_attributes[ :address ] = normalize_addr( value )
112
- elsif value =~ /^brands:/ # brands:
113
- value_brands = value[7..-1] ## cut off brands: prefix
114
- value_brands = value_brands.strip # remove leading and trailing spaces
115
- # NB: brands get processed after record gets created (see below)
116
- elsif (values.size==(index+1)) && is_taglist?( value ) # tags must be last entry
117
- logger.debug " found tags: >>#{value}<<"
118
- value_tag_keys += find_tags( value )
119
- else
120
- # issue warning: unknown type for value
121
- logger.warn "unknown type for value >#{value}< - key #{new_attributes[:key]}"
122
- end
123
- end # each value
124
-
125
- ## todo: check better style using self.find_by_key?? why? why not?
126
- rec = Brewery.find_by_key( new_attributes[ :key ] )
127
-
128
- if rec.present?
129
- logger.debug "update Brewery #{rec.id}-#{rec.key}:"
130
- else
131
- logger.debug "create Brewery:"
132
- rec = Brewery.new
133
- end
134
-
135
- logger.debug new_attributes.to_json
136
-
137
- rec.update_attributes!( new_attributes )
138
-
139
-
140
- ##############################
141
- # auto-add city if not present and country n region present
142
-
143
- if new_attributes[:city_id].blank? &&
144
- new_attributes[:country_id].present? &&
145
- new_attributes[:region_id].present?
146
-
147
- country_key = rec.country.key
148
-
149
- ###
150
- ## see textutils/helper/address_helper for details about countries supported e.g.
151
- ## github.com/rubylibs/textutils/blob/master/lib/textutils/helper/address_helper.rb
152
-
153
- if country_key == 'be' || country_key == 'at' ||
154
- country_key == 'de' ||
155
- country_key == 'cz' || country_key == 'sk' ||
156
- country_key == 'us'
157
-
158
- ## todo: how to handle nil/empty address lines?
159
-
160
- city_title = find_city_in_addr( new_attributes[:address], country_key )
161
-
162
- if city_title.present?
163
-
164
- ## for czech - some cleanup
165
- ## remove any (remaining) digits in city title
166
- city_title = city_title.gsub( /[0-9]/, '' ).strip
167
-
168
- city_values = [city_title]
169
- city_attributes = {
170
- country_id: rec.country_id,
171
- region_id: rec.region_id
172
- }
173
- # todo: add convenience helper create_or_update_from_title
174
- city = City.create_or_update_from_values( city_values, city_attributes )
175
-
176
- ### fix/todo: set new autoadd flag too?
177
- ## e.g. check if updated? e.g. timestamp created <> updated otherwise assume created?
178
-
179
- ## now at last add city_id to brewery!
180
- rec.city_id = city.id
181
- rec.save!
182
- else
183
- logger.warn "auto-add city for #{new_attributes[:key]} (#{country_key}) >>#{new_attributes[:address]}<< failed; no city title found"
184
- end
185
- end
186
- end
187
-
188
-
189
- ###################
190
- # auto-add brands if presents
191
-
192
- if value_brands.present?
193
- logger.debug " auto-adding brands >#{value_brands}<"
194
-
195
- ## todo/fix: use strip_inline_comments (e.g #() or (()) - why?? why not??)
196
- # - allows titles as usual (use new syntax for inline comments e.g. #() or (()) for example)
197
-
198
- # remove optional longer title part in () e.g. Las Palmas (de Gran Canaria), Palma (de Mallorca)
199
- value_brands = TextUtils.strip_subtitles( value_brands )
200
-
201
- brand_titles = value_brands.split( ',' )
202
-
203
- # pass 1) remove leading n trailing spaces
204
- brand_titles = brand_titles.map { |value| value.strip }
205
-
206
- brand_attribs = {
207
- brewery_id: rec.id,
208
- country_id: rec.country_id,
209
- region_id: rec.region_id,
210
- city_id: rec.city_id
211
- }
212
-
213
- brand_titles.each do |brand_title|
214
- Brand.create_or_update_from_title( brand_title, brand_attribs )
215
- end
216
- end
217
-
218
- ##################
219
- ## add taggings
220
-
221
- ##
222
- ## fix: delete all tags first or only add diff?
223
- ## fix e.g.
224
- ##
225
- # [debug] adding 1 taggings: >>trappist<<...
226
- # rake aborted!
227
- # ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: columns taggable_id, taggable_type, tag_id are not unique: INSERT INTO "taggings" ("created_at", "tag_id", "taggable_id", "taggable_type", "updated_at") VALUES (?, ?, ?, ?, ?)
228
- # if value_tag_keys.size > 0
229
-
230
- =begin
231
- value_tag_keys.uniq! # remove duplicates
232
- logger.debug " adding #{value_tag_keys.size} taggings: >>#{value_tag_keys.join('|')}<<..."
233
-
234
- ### fix/todo: check tag_ids and only update diff (add/remove ids)
235
-
236
- value_tag_keys.each do |key|
237
- tag = Tag.find_by_key( key )
238
- if tag.nil? # create tag if it doesn't exit
239
- logger.debug " creating tag >#{key}<"
240
- tag = Tag.create!( key: key )
241
- end
242
- rec.tags << tag
243
- end
244
- end
245
- =end
246
-
247
- rec # NB: return created or updated obj
248
-
249
- end # method create_or_update_from_values
250
-
251
-
252
- end # class Brewery
253
-
254
- end # module Model
255
- end # module BeerDb
256
-
@@ -1,46 +0,0 @@
1
- # encoding: UTF-8
2
-
3
-
4
- ### forward references
5
- ## require first to resolve circular references
6
-
7
-
8
- module BeerDb
9
- module Model
10
-
11
- ## todo: why? why not use include WorldDb::Models here???
12
-
13
- Continent = WorldDb::Model::Continent
14
- Country = WorldDb::Model::Country
15
- Region = WorldDb::Model::Region
16
- City = WorldDb::Model::City
17
-
18
- Tag = TagDb::Model::Tag
19
- Tagging = TagDb::Model::Tagging
20
-
21
- Prop = ConfDb::Model::Prop
22
-
23
- class Beer < ActiveRecord::Base ; end
24
- class Brand < ActiveRecord::Base ; end
25
- class Brewery < ActiveRecord::Base ; end
26
-
27
- end # module Model
28
-
29
- ## convenience alias (for better english ;-) )
30
- ## lets you use => include Models (instead of include Model)
31
- Models = Model
32
-
33
- end # module BeerDb
34
-
35
-
36
-
37
- module WorldDb
38
- module Model
39
-
40
- Beer = BeerDb::Model::Beer
41
- Brand = BeerDb::Model::Brand
42
- Brewery = BeerDb::Model::Brewery
43
-
44
- end # module Model
45
- end # module WorldDb
46
-
@@ -1,13 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module TagDb
4
- module Model
5
-
6
- class Tag
7
- has_many :beers, :through => :taggings, :source => :taggable, :source_type => 'BeerDb::Model::Beer', :class_name => 'BeerDb::Model::Beer'
8
- has_many :breweries, :through => :taggings, :source => :taggable, :source_type => 'BeerDb::Model::Brewery', :class_name => 'BeerDb::Model::Brewery'
9
- end # class Country
10
-
11
- end # module Model
12
- end # module TagDb
13
-
@@ -1,14 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module WorldDb
4
- module Model
5
-
6
- class City
7
- has_many :beers, :class_name => 'BeerDb::Model::Beer', :foreign_key => 'city_id'
8
- has_many :brands, :class_name => 'BeerDb::Model::Brand', :foreign_key => 'city_id'
9
- has_many :breweries, :class_name => 'BeerDb::Model::Brewery', :foreign_key => 'city_id'
10
- end # class Country
11
-
12
- end # module Model
13
- end # module WorldDb
14
-
@@ -1,14 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module WorldDb
4
- module Model
5
-
6
- class Country
7
- has_many :beers, :class_name => 'BeerDb::Model::Beer', :foreign_key => 'country_id'
8
- has_many :brands, :class_name => 'BeerDb::Model::Brand', :foreign_key => 'country_id'
9
- has_many :breweries, :class_name => 'BeerDb::Model::Brewery', :foreign_key => 'country_id'
10
- end # class Country
11
-
12
- end # module Model
13
- end # module WorldDb
14
-
@@ -1,14 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module WorldDb
4
- module Model
5
-
6
- class Region
7
- has_many :beers, :class_name => 'BeerDb::Model::Beer', :foreign_key => 'region_id'
8
- has_many :brands, :class_name => 'BeerDb::Model::Brand', :foreign_key => 'region_id'
9
- has_many :breweries, :class_name => 'BeerDb::Model::Brewery', :foreign_key => 'region_id'
10
- end # class Region
11
-
12
- end # module Model
13
- end # module WorldDb
14
-
data/lib/beerdb/reader.rb DELETED
@@ -1,219 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module BeerDb
4
-
5
-
6
- module Matcher
7
-
8
- def match_beers_for_country( name, &blk )
9
- match_xxx_for_country( name, 'beers', &blk )
10
- end
11
-
12
- def match_beers_for_country_n_region( name, &blk )
13
- match_xxx_for_country_n_region( name, 'beers', &blk )
14
- end
15
-
16
- def match_breweries_for_country( name, &blk )
17
- match_xxx_for_country( name, 'breweries', &blk )
18
- end
19
-
20
- def match_breweries_for_country_n_region( name, &blk )
21
- match_xxx_for_country_n_region( name, 'breweries', &blk )
22
- end
23
-
24
- def match_brewpubs_for_country( name, &blk )
25
- match_xxx_for_country( name, 'brewpubs', &blk )
26
- end
27
-
28
- def match_brewpubs_for_country_n_region( name, &blk )
29
- match_xxx_for_country_n_region( name, 'brewpubs', &blk )
30
- end
31
-
32
-
33
- end # module Matcher
34
-
35
-
36
- class ReaderBase
37
-
38
- include LogUtils::Logging
39
-
40
- include BeerDb::Models
41
-
42
- include WorldDb::Matcher ## fix: move to BeerDb::Matcher module ??? - cleaner?? why? why not?
43
- include BeerDb::Matcher # lets us use match_teams_for_country etc.
44
-
45
-
46
- def load_setup( name )
47
- reader = create_fixture_reader( name ) ### "virtual" method - required by concrete class
48
-
49
- reader.each do |fixture_name|
50
- load( fixture_name )
51
- end
52
- end # method load_setup
53
-
54
-
55
-
56
- def load( name )
57
-
58
- if match_beers_for_country_n_region( name ) do |country_key, region_key|
59
- load_beers_for_country_n_region( country_key, region_key, name )
60
- end
61
- elsif match_beers_for_country( name ) do |country_key|
62
- load_beers_for_country( country_key, name )
63
- end
64
- elsif match_breweries_for_country_n_region( name ) do |country_key, region_key|
65
- load_breweries_for_country_n_region( country_key, region_key, name )
66
- end
67
- elsif match_breweries_for_country( name ) do |country_key|
68
- load_breweries_for_country( country_key, name )
69
- end
70
- elsif match_brewpubs_for_country_n_region( name ) do |country_key, region_key|
71
- load_breweries_for_country_n_region( country_key, region_key, name, brewpub: true )
72
- end
73
- elsif match_brewpubs_for_country( name ) do |country_key|
74
- load_breweries_for_country( country_key, name, brewpub: true )
75
- end
76
- else
77
- logger.error "unknown beer.db fixture type >#{name}<"
78
- # todo/fix: exit w/ error
79
- end
80
- end
81
-
82
-
83
- def load_beers_for_country_n_region( country_key, region_key, name, more_attribs={} )
84
- country = Country.find_by_key!( country_key )
85
- logger.debug "Country #{country.key} >#{country.title} (#{country.code})<"
86
- more_attribs[ :country_id ] = country.id
87
-
88
- # NB: region lookup requires country id (region key only unique for country)
89
- region = Region.find_by_key_and_country_id( region_key, country.id )
90
- if region.nil?
91
- # note: allow unknown region keys; issue warning n skip region
92
- logger.warn "Region w/ key >#{region_key}< not found; skip adding region"
93
- else
94
- logger.debug "Region #{region.key} >#{region.title}<"
95
- more_attribs[ :region_id ] = region.id
96
- end
97
-
98
- more_attribs[ :txt ] = name # store source ref
99
-
100
- load_beers_worker( name, more_attribs )
101
- end
102
-
103
- def load_beers_for_country( country_key, name, more_attribs={} )
104
- country = Country.find_by_key!( country_key )
105
- logger.debug "Country #{country.key} >#{country.title} (#{country.code})<"
106
-
107
- more_attribs[ :country_id ] = country.id
108
-
109
- more_attribs[ :txt ] = name # store source ref
110
-
111
- load_beers_worker( name, more_attribs )
112
- end
113
-
114
-
115
- def load_beers_worker( name, more_attribs={} )
116
-
117
- reader = create_beers_reader( name, more_attribs ) ### "virtual" method - required by concrete class
118
-
119
- ### todo: cleanup - check if [] works for build_title...
120
- # better cleaner way ???
121
- if more_attribs[:region_id].present?
122
- known_breweries_source = Brewery.where( region_id: more_attribs[:region_id] )
123
- elsif more_attribs[:country_id].present?
124
- known_breweries_source = Brewery.where( country_id: more_attribs[:country_id] )
125
- else
126
- logger.warn "no region or country specified; use empty brewery ary for header mapper"
127
- known_breweries_source = []
128
- end
129
-
130
- known_breweries = TextUtils.build_title_table_for( known_breweries_source )
131
-
132
-
133
- reader.each_line do |new_attributes, values|
134
-
135
- ## note: check for header attrib; if present remove
136
- ### todo: cleanup code later
137
- ## fix: add to new_attributes hash instead of values ary
138
- ## - fix: match_brewery() move region,city code out of values loop for reuse at the end
139
- if new_attributes[:header].present?
140
- brewery_line = new_attributes[:header].dup # note: make sure we make a copy; will use in-place string ops
141
- new_attributes.delete(:header) ## note: do NOT forget to remove from hash!
142
-
143
- logger.debug " trying to find brewery in line >#{brewery_line}<"
144
- ## todo: check what map_titles_for! returns (nothing ???)
145
- TextUtils.map_titles_for!( 'brewery', brewery_line, known_breweries )
146
- brewery_key = TextUtils.find_key_for!( 'brewery', brewery_line )
147
- logger.debug " brewery_key = >#{brewery_key}<"
148
- unless brewery_key.nil?
149
- ## bingo! add brewery_id upfront, that is, as first value in ary
150
- values = values.unshift "by:#{brewery_key}"
151
- end
152
- end
153
-
154
- Beer.create_or_update_from_attribs( new_attributes, values )
155
- end # each_line
156
- end
157
-
158
-
159
- def load_breweries_for_country_n_region( country_key, region_key, name, more_attribs={} )
160
- country = Country.find_by_key!( country_key )
161
- logger.debug "Country #{country.key} >#{country.title} (#{country.code})<"
162
-
163
- more_attribs[ :country_id ] = country.id
164
-
165
- # note: region lookup requires country id (region key only unique for country)
166
- region = Region.find_by_key_and_country_id( region_key, country.id )
167
- if region.nil?
168
- # note: allow unknown region keys; issue warning n skip region
169
- logger.warn "Region w/ key >#{region_key}< not found; skip adding region"
170
- else
171
- logger.debug "Region #{region.key} >#{region.title}<"
172
- more_attribs[ :region_id ] = region.id
173
- end
174
-
175
- more_attribs[ :txt ] = name # store source ref
176
-
177
- load_breweries_worker( name, more_attribs )
178
- end
179
-
180
- def load_breweries_for_country( country_key, name, more_attribs={} )
181
- country = Country.find_by_key!( country_key )
182
- logger.debug "Country #{country.key} >#{country.title} (#{country.code})<"
183
-
184
- more_attribs[ :country_id ] = country.id
185
-
186
- more_attribs[ :txt ] = name # store source ref
187
-
188
- load_breweries_worker( name, more_attribs )
189
- end
190
-
191
- def load_breweries_worker( name, more_attribs={} )
192
-
193
- if name =~ /\(m\)/ # check for (m) mid-size/medium marker -todo- use $?? must be last?
194
- more_attribs[ :prod_m ] = true
195
- elsif name =~ /\(l\)/ # check for (l) large marker - todo - use $?? must be last?
196
- more_attribs[ :prod_l ] = true
197
- else
198
- ## no marker; do nothing
199
- end
200
-
201
- reader = create_breweries_reader( name, more_attribs ) ### "virtual" method - required by concrete class
202
-
203
- reader.each_line do |new_attributes, values|
204
-
205
- #######
206
- # fix: move to (inside)
207
- # Brewery.create_or_update_from_attribs ||||
208
- ## note: group header not used for now; do NOT forget to remove from hash!
209
- if new_attributes[:header].present?
210
- logger.warn "removing unused group header #{new_attributes[:header]}"
211
- new_attributes.delete(:header) ## note: do NOT forget to remove from hash!
212
- end
213
-
214
- Brewery.create_or_update_from_attribs( new_attributes, values )
215
- end # each_line
216
- end
217
-
218
- end # class ReaderBase
219
- end # module BeerDb
@@ -1,62 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module BeerDb
4
-
5
- ## todo: "old" classic reader - rename to FileReader ?? why? why not?
6
-
7
- class Reader < ReaderBase
8
-
9
- def initialize( include_path, opts = {} )
10
- @include_path = include_path
11
- end
12
-
13
- def create_fixture_reader( name )
14
- path = "#{@include_path}/#{name}.txt"
15
-
16
- logger.info "parsing data (setup) '#{name}' (#{path})..."
17
-
18
- FixtureReader.from_file( path )
19
- end
20
-
21
- def create_beers_reader( name, more_attribs={} )
22
- real_name = name_to_real_name( name )
23
-
24
- path = "#{@include_path}/#{real_name}.txt"
25
-
26
- logger.info "parsing data (beers) '#{name}' (#{path})..."
27
-
28
- ValuesReader.from_file( path, more_attribs )
29
- ## ValuesReaderV2.new( name, @include_path, more_attribs )
30
- end
31
-
32
- def create_breweries_reader( name, more_attribs={} )
33
- real_name = name_to_real_name( name )
34
-
35
- path = "#{@include_path}/#{real_name}.txt"
36
-
37
- logger.info "parsing data (breweries) '#{name}' (#{path})..."
38
-
39
- ValuesReader.from_file( path, more_attribs )
40
- ## ValuesReaderV2.new( name, @include_path, more_attribs )
41
- end
42
-
43
- private
44
-
45
- def name_to_real_name( name )
46
- # map name to real_name path
47
- # name might include !/ for virtual path (gets cut off)
48
- # e.g. at-austria!/w-wien/beers becomse w-wien/beers
49
- pos = name.index( '!/')
50
- if pos.nil?
51
- name # not found; real path is the same as name
52
- else
53
- # cut off everything until !/ e.g.
54
- # at-austria!/w-wien/beers becomes
55
- # w-wien/beers
56
- name[ (pos+2)..-1 ]
57
- end
58
- end
59
-
60
- end # class Reader
61
- end # module BeerDb
62
-