winedb 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -3,4 +3,15 @@ Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
5
  lib/winedb.rb
6
+ lib/winedb/models/city.rb
7
+ lib/winedb/models/country.rb
8
+ lib/winedb/models/forward.rb
9
+ lib/winedb/models/region.rb
10
+ lib/winedb/models/tag.rb
11
+ lib/winedb/models/wine.rb
12
+ lib/winedb/models/winery.rb
13
+ lib/winedb/reader.rb
14
+ lib/winedb/schema.rb
6
15
  lib/winedb/version.rb
16
+ test/helper.rb
17
+ test/test_models.rb
@@ -1,7 +1,28 @@
1
1
 
2
2
 
3
+ # 3rd party gems / libs
4
+
5
+ require 'active_record' ## todo: add sqlite3? etc.
6
+
7
+ require 'logutils'
8
+ require 'textutils'
9
+ require 'worlddb'
10
+
11
+
12
+ ### our own code
13
+
3
14
  require 'winedb/version' # let it always go first
15
+ require 'winedb/schema'
16
+
17
+ require 'winedb/models/forward'
18
+ require 'winedb/models/city'
19
+ require 'winedb/models/country'
20
+ require 'winedb/models/region'
21
+ require 'winedb/models/tag'
22
+ require 'winedb/models/wine'
23
+ require 'winedb/models/winery'
4
24
 
25
+ require 'winedb/reader'
5
26
 
6
27
  module WineDb
7
28
 
@@ -13,6 +34,30 @@ module WineDb
13
34
  "#{File.expand_path( File.dirname(File.dirname(__FILE__)) )}"
14
35
  end
15
36
 
37
+ def self.create
38
+ CreateDb.new.up
39
+
40
+ WineDb::Model::Prop.create!( key: 'db.schema.wine.version', value: VERSION )
41
+ end
42
+
43
+
44
+ def self.read( ary, include_path )
45
+ reader = Reader.new( include_path )
46
+ ary.each do |name|
47
+ reader.load( name )
48
+ end
49
+ end
50
+
51
+ def self.read_setup( setup, include_path, opts={} )
52
+ reader = Reader.new( include_path, opts )
53
+ reader.load_setup( setup )
54
+ end
55
+
56
+ def self.read_all( include_path, opts={} ) # load all builtins (using plain text reader); helper for convenience
57
+ read_setup( 'setups/all', include_path, opts )
58
+ end # method read_all
59
+
60
+
16
61
  end # module WineDb
17
62
 
18
63
 
@@ -0,0 +1,11 @@
1
+ module WorldDb
2
+ module Model
3
+
4
+ class City
5
+ has_many :wines, class_name: 'WineDb::Model::Wine', foreign_key: 'city_id'
6
+ has_many :wineries, class_name: 'WineDb::Model::Winery', foreign_key: 'city_id'
7
+ end # class Country
8
+
9
+
10
+ end # module Model
11
+ end # module WorldDb
@@ -0,0 +1,13 @@
1
+ module WorldDb
2
+ module Model
3
+
4
+
5
+ class Country
6
+ has_many :wines, class_name: 'WineDb::Model::Wine', foreign_key: 'country_id'
7
+ has_many :wineries, class_name: 'WineDb::Model::Winery', foreign_key: 'country_id'
8
+ end # class Country
9
+
10
+
11
+ end # module Model
12
+ end # module WorldDb
13
+
@@ -0,0 +1,39 @@
1
+ ### forward references
2
+ ## require first to resolve circular references
3
+
4
+
5
+ module WineDb
6
+ module Model
7
+
8
+ ## todo: why? why not use include WorldDb::Models here???
9
+
10
+ Continent = WorldDb::Model::Continent
11
+ Country = WorldDb::Model::Country
12
+ Region = WorldDb::Model::Region
13
+ City = WorldDb::Model::City
14
+
15
+ Tag = WorldDb::Model::Tag
16
+ Tagging = WorldDb::Model::Tagging
17
+
18
+ Prop = WorldDb::Model::Prop
19
+
20
+ class Wine < ActiveRecord::Base ; end
21
+ class Winery < ActiveRecord::Base ; end
22
+
23
+ end # module Model
24
+
25
+ ## note: for convenciene (and compatibility) add alias Models for Model namespace
26
+ ## e.g lets you use include WineDb::Models
27
+ Models = Model
28
+
29
+ end # module WineDb
30
+
31
+
32
+ module WorldDb
33
+ module Model
34
+
35
+ Wine = WineDb::Model::Wine
36
+ Winery = WineDb::Model::Winery
37
+
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ module WorldDb
2
+ module Model
3
+
4
+ class Region
5
+ has_many :wines, class_name: 'WineDb::Model::Wine', foreign_key: 'region_id'
6
+ has_many :wineries, class_name: 'WineDb::Model::Winery', foreign_key: 'region_id'
7
+ end # class Region
8
+
9
+ end # module Model
10
+ end # module WorldDb
@@ -0,0 +1,12 @@
1
+ module WorldDb
2
+ module Model
3
+
4
+
5
+ class Tag
6
+ has_many :wines, :through => :taggings, :source => :taggable, source_type: 'WineDb::Model::Wine', class_name: 'WineDb::Model::Wine'
7
+ has_many :wineries, :through => :taggings, :source => :taggable, source_type: 'WineDb::Model::Winery', class_name: 'WineDb::Model::Winery'
8
+ end # class Country
9
+
10
+
11
+ end # module Model
12
+ end # module WorldDb
@@ -0,0 +1,123 @@
1
+ # encoding: UTF-8
2
+
3
+ module WineDb
4
+ module Model
5
+
6
+ class Wine < 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?, self.is_address?, is_taglist? etc.
13
+
14
+ belongs_to :country, class_name: 'WorldDb::Model::Country', foreign_key: 'country_id'
15
+ belongs_to :region, class_name: 'WorldDb::Model::Region', foreign_key: 'region_id'
16
+ belongs_to :city, class_name: 'WorldDb::Model::City', foreign_key: 'city_id'
17
+
18
+ belongs_to :winery, :class_name => 'WineDb::Model::Winery', foreign_key: 'winery_id'
19
+
20
+ has_many :taggings, :as => :taggable, class_name: 'WorldDb::Model::Tagging'
21
+ has_many :tags, :through => :taggings, class_name: 'WorldDb::Model::Tag'
22
+
23
+ validates :key, :format => { :with => /^[a-z][a-z0-9]+$/, :message => 'expected two or more lowercase letters a-z or 0-9 digits' }
24
+
25
+
26
+
27
+ def self.create_or_update_from_values( values, more_attribs={} )
28
+
29
+ attribs, more_values = find_key_n_title( values )
30
+ attribs = attribs.merge( more_attribs )
31
+
32
+ # check for optional values
33
+ Wine.create_or_update_from_attribs( attribs, more_values )
34
+ end
35
+
36
+
37
+ def self.create_or_update_from_attribs( attribs, values )
38
+
39
+ # fix: add/configure logger for ActiveRecord!!!
40
+ logger = LogKernel::Logger.root
41
+
42
+ value_tag_keys = []
43
+
44
+ ### check for "default" tags - that is, if present attribs[:tags] remove from hash
45
+ value_tag_keys += find_tags_in_attribs!( attribs )
46
+
47
+ ## check for optional values
48
+ values.each_with_index do |value,index|
49
+ if match_country(value) do |country|
50
+ attribs[ :country_id ] = country.id
51
+ end
52
+ elsif match_region_for_country(value, attribs[:country_id]) do |region|
53
+ attribs[ :region_id ] = region.id
54
+ end
55
+ elsif match_city(value) do |city|
56
+ if city.present?
57
+ attribs[ :city_id ] = city.id
58
+ else
59
+ ## todo/fix: add strict mode flag - fail w/ exit 1 in strict mode
60
+ logger.warn "city with key #{value[5..-1]} missing for beer #{attribs[:key]}"
61
+ end
62
+ end
63
+ elsif match_year( value ) do |num| # founded/established year e.g. 1776
64
+ attribs[ :since ] = num
65
+ end
66
+ elsif match_website( value ) do |website| # check for url/internet address e.g. www.ottakringer.at
67
+ attribs[ :web ] = website
68
+ end
69
+ elsif match_abv( value ) do |num| # abv (alcohol by volume)
70
+ # nb: also allows leading < e.g. <0.5%
71
+ attribs[ :abv ] = num
72
+ end
73
+ elsif (values.size==(index+1)) && is_taglist?( value ) # tags must be last entry
74
+ logger.debug " found tags: >>#{value}<<"
75
+ value_tag_keys += find_tags( value )
76
+ else
77
+ # issue warning: unknown type for value
78
+ logger.warn "unknown type for value >#{value}< - key #{attribs[:key]}"
79
+ end
80
+ end # each value
81
+
82
+ # rec = Wine.find_by_key_and_country_id( attribs[ :key ], attribs[ :country_id] )
83
+ rec = Wine.find_by_key( attribs[ :key ] )
84
+
85
+ if rec.present?
86
+ logger.debug "update Wine #{rec.id}-#{rec.key}:"
87
+ else
88
+ logger.debug "create Wine:"
89
+ rec = Wine.new
90
+ end
91
+
92
+ logger.debug attribs.to_json
93
+
94
+ rec.update_attributes!( attribs )
95
+
96
+ ##################
97
+ # add taggings
98
+
99
+ if value_tag_keys.size > 0
100
+
101
+ value_tag_keys.uniq! # remove duplicates
102
+ logger.debug " adding #{value_tag_keys.size} taggings: >>#{value_tag_keys.join('|')}<<..."
103
+
104
+ ### fix/todo: check tag_ids and only update diff (add/remove ids)
105
+
106
+ value_tag_keys.each do |key|
107
+ tag = Tag.find_by_key( key )
108
+ if tag.nil? # create tag if it doesn't exit
109
+ logger.debug " creating tag >#{key}<"
110
+ tag = Tag.create!( key: key )
111
+ end
112
+ rec.tags << tag
113
+ end
114
+ end
115
+
116
+ rec # NB: return created or updated obj
117
+
118
+ end # method create_or_update_from_values
119
+
120
+ end # class Wine
121
+
122
+ end # module Model
123
+ end # module WineDb
@@ -0,0 +1,172 @@
1
+ # encoding: UTF-8
2
+
3
+ module WineDb
4
+ module Model
5
+
6
+ class Winery < 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 = 'wineries'
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 :wines, class_name: 'WineDb::Model::Wine', foreign_key: 'wine_id'
22
+
23
+ has_many :taggings, :as => :taggable, class_name: 'WorldDb::Model::Tagging'
24
+ has_many :tags, :through => :taggings, class_name: 'WorldDb::Model::Tag'
25
+
26
+ validates :key, :format => { :with => /^[a-z][a-z0-9]+$/, :message => 'expected two or more lowercase letters a-z or 0-9 digits' }
27
+
28
+
29
+ def self.create_or_update_from_values( values, more_attribs={} )
30
+ attribs, more_values = find_key_n_title( values )
31
+ attribs = attribs.merge( more_attribs )
32
+
33
+ # check for optional values
34
+ Winery.create_or_update_from_attribs( attribs, more_values )
35
+ end
36
+
37
+
38
+ def self.create_or_update_from_attribs( new_attributes, values )
39
+
40
+ ## fix: add/configure logger for ActiveRecord!!!
41
+ logger = LogKernel::Logger.root
42
+
43
+ value_tag_keys = []
44
+
45
+ ## check for grades (e.g. ***/**/*) in titles (will add new_attributes[:grade] to hash)
46
+ ## if grade missing; set default to 4; lets us update overwrite 1,2,3 values on update
47
+ new_attributes[ :grade ] ||= 4
48
+
49
+ ### check for "default" tags - that is, if present new_attributes[:tags] remove from hash
50
+ value_tag_keys += find_tags_in_attribs!( new_attributes )
51
+
52
+ ## check for optional values
53
+ values.each_with_index do |value,index|
54
+ if match_country(value) do |country|
55
+ new_attributes[ :country_id ] = country.id
56
+ end
57
+ elsif match_region_for_country(value,new_attributes[:country_id]) do |region|
58
+ new_attributes[ :region_id ] = region.id
59
+ end
60
+ elsif match_city(value) do |city|
61
+ if city.present?
62
+ new_attributes[ :city_id ] = city.id
63
+ else
64
+ ## todo/fix: add strict mode flag - fail w/ exit 1 in strict mode
65
+ logger.warn "city with key #{value[5..-1]} missing - for winery #{new_attributes[:key]}"
66
+ end
67
+
68
+ ## for easy queries: cache region_id (from city)
69
+ # - check if city w/ region if yes, use it for winery too
70
+ if city.present? && city.region.present?
71
+ new_attributes[ :region_id ] = city.region.id
72
+ end
73
+ end
74
+ elsif match_year( value ) do |num| # founded/established year e.g. 1776
75
+ new_attributes[ :since ] = num
76
+ end
77
+ elsif match_website( value ) do |website| # check for url/internet address e.g. www.ottakringer.at
78
+ # fix: support more url format (e.g. w/o www. - look for .com .country code etc.)
79
+ new_attributes[ :web ] = website
80
+ end
81
+ elsif is_address?( value ) # if value includes // assume address e.g. 3970 Weitra // Sparkasseplatz 160
82
+ new_attributes[ :address ] = normalize_addr( value )
83
+ elsif (values.size==(index+1)) && is_taglist?( value ) # tags must be last entry
84
+ logger.debug " found tags: >>#{value}<<"
85
+ value_tag_keys += find_tags( value )
86
+ else
87
+ # issue warning: unknown type for value
88
+ logger.warn "unknown type for value >#{value}< - key #{new_attributes[:key]}"
89
+ end
90
+ end # each value
91
+
92
+ ## todo: check better style using self.find_by_key?? why? why not?
93
+ rec = Winery.find_by_key( new_attributes[ :key ] )
94
+
95
+ if rec.present?
96
+ logger.debug "update Winery #{rec.id}-#{rec.key}:"
97
+ else
98
+ logger.debug "create Winery:"
99
+ rec = Winery.new
100
+ end
101
+
102
+ logger.debug new_attributes.to_json
103
+
104
+ rec.update_attributes!( new_attributes )
105
+
106
+
107
+ ##############################
108
+ # auto-add city if not present and country n region present
109
+
110
+ if new_attributes[:city_id].blank? &&
111
+ new_attributes[:country_id].present? &&
112
+ new_attributes[:region_id].present?
113
+
114
+ country_key = rec.country.key
115
+
116
+ if country_key == 'at' || country_key == 'de'
117
+
118
+ ## todo: how to handle nil/empty address lines?
119
+
120
+ city_title = find_city_in_addr( new_attributes[:address], country_key )
121
+
122
+ if city_title.present?
123
+
124
+ city_values = [city_title]
125
+ city_attributes = {
126
+ country_id: rec.country_id,
127
+ region_id: rec.region_id
128
+ }
129
+ # todo: add convenience helper create_or_update_from_title
130
+ city = City.create_or_update_from_values( city_values, city_attributes )
131
+
132
+ ### fix/todo: set new autoadd flag too?
133
+ ## e.g. check if updated? e.g. timestamp created <> updated otherwise assume created?
134
+
135
+ ## now at last add city_id to winery!
136
+ rec.city_id = city.id
137
+ rec.save!
138
+ else
139
+ logger.warn "auto-add city for #{new_attributes[:key]} (#{country_key}) >>#{new_attributes[:address]}<< failed; no city title found"
140
+ end
141
+ end
142
+ end
143
+
144
+ ##################
145
+ ## add taggings
146
+
147
+ if value_tag_keys.size > 0
148
+
149
+ value_tag_keys.uniq! # remove duplicates
150
+ logger.debug " adding #{value_tag_keys.size} taggings: >>#{value_tag_keys.join('|')}<<..."
151
+
152
+ ### fix/todo: check tag_ids and only update diff (add/remove ids)
153
+
154
+ value_tag_keys.each do |key|
155
+ tag = Tag.find_by_key( key )
156
+ if tag.nil? # create tag if it doesn't exit
157
+ logger.debug " creating tag >#{key}<"
158
+ tag = Tag.create!( key: key )
159
+ end
160
+ rec.tags << tag
161
+ end
162
+ end
163
+
164
+ rec # NB: return created or updated obj
165
+
166
+ end # method create_or_update_from_values
167
+
168
+
169
+ end # class Winery
170
+
171
+ end # module Model
172
+ end # module WineDb
@@ -0,0 +1,156 @@
1
+ # encoding: UTF-8
2
+
3
+ module WineDb
4
+
5
+
6
+ module Matcher
7
+
8
+ def match_wines_for_country( name, &blk )
9
+ match_xxx_for_country( name, 'wines', &blk )
10
+ end
11
+
12
+ # def match_wines_for_country_n_region( name, &blk )
13
+ # match_xxx_for_country_n_region( name, 'wines', &blk )
14
+ # end
15
+
16
+ def match_wineries_for_country( name, &blk )
17
+ match_xxx_for_country( name, 'wineries', &blk )
18
+ end
19
+
20
+ # def match_wineries_for_country_n_region( name, &blk )
21
+ # match_xxx_for_country_n_region( name, 'wineries', &blk )
22
+ # end
23
+
24
+ end # module Matcher
25
+
26
+
27
+ class Reader
28
+
29
+ include LogUtils::Logging
30
+
31
+ include WineDb::Models
32
+
33
+ include WorldDb::Matcher ## fix: move to WineDb::Matcher module ??? - cleaner?? why? why not?
34
+ include WineDb::Matcher # lets us use match_teams_for_country etc.
35
+
36
+ attr_reader :include_path
37
+
38
+
39
+ def initialize( include_path, opts = {} )
40
+ @include_path = include_path
41
+ end
42
+
43
+
44
+ def load_setup( name )
45
+ path = "#{include_path}/#{name}.yml"
46
+
47
+ logger.info "parsing data '#{name}' (#{path})..."
48
+
49
+ reader = FixtureReader.new( path )
50
+
51
+ reader.each do |fixture_name|
52
+ load( fixture_name )
53
+ end
54
+ end # method load_setup
55
+
56
+
57
+ def load( name )
58
+
59
+ if match_wines_for_country( name ) do |country_key|
60
+ load_wines_for_country( country_key, name )
61
+ end
62
+ elsif match_wineries_for_country( name ) do |country_key|
63
+ load_wineries_for_country( country_key, name )
64
+ end
65
+ else
66
+ logger.error "unknown wine.db fixture type >#{name}<"
67
+ # todo/fix: exit w/ error
68
+ end
69
+ end
70
+
71
+
72
+ def load_wines_for_country( country_key, name, more_attribs={} )
73
+ country = Country.find_by_key!( country_key )
74
+ logger.debug "Country #{country.key} >#{country.title} (#{country.code})<"
75
+
76
+ more_attribs[ :country_id ] = country.id
77
+
78
+ more_attribs[ :txt ] = name # store source ref
79
+
80
+ load_wines_worker( name, more_attribs )
81
+ end
82
+
83
+
84
+ def load_wines_worker( name, more_attribs={} )
85
+ reader = ValuesReaderV2.new( name, include_path, more_attribs )
86
+
87
+ ### todo: cleanup - check if [] works for build_title...
88
+ # better cleaner way ???
89
+ if more_attribs[:region_id].present?
90
+ known_wineries_source = Winery.where( region_id: more_attribs[:region_id] )
91
+ elsif more_attribs[:country_id].present?
92
+ known_wineries_source = Winery.where( country_id: more_attribs[:country_id] )
93
+ else
94
+ logger.warn "no region or country specified; use empty winery ary for header mapper"
95
+ known_wineries_source = []
96
+ end
97
+
98
+ known_wineries = TextUtils.build_title_table_for( known_wineries_source )
99
+
100
+ reader.each_line do |new_attributes, values|
101
+
102
+ ## note: check for header attrib; if present remove
103
+ ### todo: cleanup code later
104
+ ## fix: add to new_attributes hash instead of values ary
105
+ ## - fix: match_winery() move region,city code out of values loop for reuse at the end
106
+ if new_attributes[:header].present?
107
+ winery_line = new_attributes[:header].dup # note: make sure we make a copy; will use in-place string ops
108
+ new_attributes.delete(:header) ## note: do NOT forget to remove from hash!
109
+
110
+ logger.debug " trying to find winery in line >#{winery_line}<"
111
+ ## todo: check what map_titles_for! returns (nothing ???)
112
+ TextUtils.map_titles_for!( 'winery', winery_line, known_wineries )
113
+ winery_key = TextUtils.find_key_for!( 'winery', winery_line )
114
+ logger.debug " winery_key = >#{winery_key}<"
115
+ unless winery_key.nil?
116
+ ## bingo! add winery_id upfront, that is, as first value in ary
117
+ values = values.unshift "winery:#{winery_key}"
118
+ end
119
+ end
120
+
121
+ Wine.create_or_update_from_attribs( new_attributes, values )
122
+ end # each_line
123
+ end
124
+
125
+
126
+ def load_wineries_for_country( country_key, name, more_attribs={} )
127
+ country = Country.find_by_key!( country_key )
128
+ logger.debug "Country #{country.key} >#{country.title} (#{country.code})<"
129
+
130
+ more_attribs[ :country_id ] = country.id
131
+
132
+ more_attribs[ :txt ] = name # store source ref
133
+
134
+ load_wineries_worker( name, more_attribs )
135
+ end
136
+
137
+ def load_wineries_worker( name, more_attribs={} )
138
+ reader = ValuesReaderV2.new( name, include_path, more_attribs )
139
+
140
+ reader.each_line do |new_attributes, values|
141
+
142
+ #######
143
+ # fix: move to (inside)
144
+ # Winery.create_or_update_from_attribs ||||
145
+ ## note: group header not used for now; do NOT forget to remove from hash!
146
+ if new_attributes[:header].present?
147
+ logger.warn "removing unused group header #{new_attributes[:header]}"
148
+ new_attributes.delete(:header) ## note: do NOT forget to remove from hash!
149
+ end
150
+
151
+ Winery.create_or_update_from_attribs( new_attributes, values )
152
+ end # each_line
153
+ end
154
+
155
+ end # class Reader
156
+ end # module WineDb
@@ -0,0 +1,75 @@
1
+ # encoding: UTF-8
2
+
3
+ module WineDb
4
+
5
+ class CreateDb < ActiveRecord::Migration
6
+
7
+
8
+ def up
9
+
10
+ create_table :wines do |t|
11
+ t.string :key, null: false # import/export key
12
+ t.string :title, null: false
13
+ t.string :synonyms # comma separated list of synonyms
14
+
15
+ t.string :web # optional url link (e.g. )
16
+ t.integer :since # optional year (e.g. 1896)
17
+
18
+ ## check: why decimal and not float?
19
+ t.decimal :abv # Alcohol by volume (abbreviated as ABV, abv, or alc/vol) e.g. 4.9 %
20
+
21
+ t.references :winery # optional (for now)
22
+
23
+
24
+ t.string :txt # source ref
25
+ t.boolean :txt_auto, null: false, default: false # inline? got auto-added?
26
+
27
+
28
+ t.references :country, null: false
29
+ t.references :region # optional
30
+ t.references :city # optional
31
+
32
+ t.timestamps
33
+ end
34
+
35
+
36
+ create_table :wineries do |t|
37
+ t.string :key, null: false # import/export key
38
+ t.string :title, null: false
39
+ t.string :synonyms # comma separated list of synonyms
40
+ t.string :address
41
+ t.integer :since
42
+ ## renamed to founded to since
43
+ ## t.integer :founded # year founded/established - todo/fix: rename to since?
44
+ t.integer :closed # optional; year winery closed
45
+
46
+ t.integer :area # in ha e.g. 8 ha # Weingarten/rebflaeche
47
+
48
+ # use stars in .txt e.g. # ***/**/*/- => 1/2/3/4
49
+ t.integer :grade, null: false, default: 4
50
+
51
+
52
+ t.string :txt # source ref
53
+ t.boolean :txt_auto, null: false, default: false # inline? got auto-added?
54
+
55
+ t.string :web # optional web page (e.g. www.ottakringer.at)
56
+ t.string :wikipedia # optional wiki(pedia page)
57
+
58
+
59
+ t.references :country, null: false
60
+ t.references :region # optional
61
+ t.references :city # optional
62
+
63
+ t.timestamps
64
+ end
65
+
66
+ end # method up
67
+
68
+ def down
69
+ raise ActiveRecord::IrreversibleMigration
70
+ end
71
+
72
+
73
+ end # class CreateDb
74
+
75
+ end # module WineDb
@@ -1,4 +1,4 @@
1
1
 
2
2
  module WineDb
3
- VERSION = '0.0.1'
3
+ VERSION = '0.1.0'
4
4
  end
@@ -0,0 +1,76 @@
1
+ # encoding: UTF-8
2
+
3
+ ## $:.unshift(File.dirname(__FILE__))
4
+
5
+ ## minitest setup
6
+
7
+ # require 'minitest/unit'
8
+ require 'minitest/autorun'
9
+
10
+ # include MiniTest::Unit # lets us use TestCase instead of MiniTest::Unit::TestCase
11
+
12
+
13
+ # ruby stdlibs
14
+
15
+ require 'json'
16
+ require 'uri'
17
+ require 'pp'
18
+
19
+ # ruby gems
20
+
21
+ require 'active_record'
22
+
23
+ # our own code
24
+
25
+ require 'winedb'
26
+ require 'logutils/db' # NB: explict require required for LogDb (not automatic)
27
+
28
+ Country = WorldDb::Model::Country
29
+ Region = WorldDb::Model::Region
30
+ City = WorldDb::Model::City
31
+
32
+ ## todo: get all models aliases (e.g. from console script)
33
+
34
+ Wine = WineDb::Model::Wine
35
+ Winery = WineDb::Model::Winery
36
+
37
+
38
+ def setup_in_memory_db
39
+ # Database Setup & Config
40
+
41
+ db_config = {
42
+ adapter: 'sqlite3',
43
+ database: ':memory:'
44
+ }
45
+
46
+ pp db_config
47
+
48
+ ActiveRecord::Base.logger = Logger.new( STDOUT )
49
+ ## ActiveRecord::Base.colorize_logging = false - no longer exists - check new api/config setting?
50
+
51
+ ## NB: every connect will create a new empty in memory db
52
+ ActiveRecord::Base.establish_connection( db_config )
53
+
54
+
55
+ ## build schema
56
+
57
+ LogDb.create
58
+ WorldDb.create
59
+ WineDb.create
60
+ end
61
+
62
+
63
+ def fillup_in_memory_db
64
+ ## add some counties
65
+
66
+ at = Country.create!( key: 'at', title: 'Austria', code: 'AUT', pop: 0, area: 0 )
67
+ n = Region.create!( key: 'n', title: 'Niederösterreich', country_id: at.id )
68
+
69
+ end
70
+
71
+ setup_in_memory_db()
72
+ fillup_in_memory_db()
73
+
74
+ AT = Country.find_by_key!( 'at' )
75
+ N = Region.find_by_key!( 'n' )
76
+
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_helper.rb
6
+ # or better
7
+ # rake test
8
+
9
+ require 'helper'
10
+
11
+
12
+ class TestModels < MiniTest::Unit::TestCase
13
+
14
+ def test_load_wine_values
15
+
16
+ key = 'gruenerveltlinerspiegel'
17
+
18
+ values = [
19
+ 'Grüner Veltliner Spiegel',
20
+ '12.3 %',
21
+ 'gv'
22
+ ]
23
+
24
+ more_attribs = {
25
+ country_id: AT.id
26
+ }
27
+
28
+ wine = Wine.create_or_update_from_values( values, more_attribs )
29
+
30
+ wine2 = Wine.find_by_key!( key )
31
+ assert_equal wine.id, wine2.id
32
+
33
+ assert_equal wine.title, values[0]
34
+ assert_equal wine.country_id, AT.id
35
+ assert_equal wine.country.title, AT.title
36
+ assert_equal wine.abv, 12.3
37
+ end
38
+
39
+ def test_load_winery_values
40
+
41
+ key = 'antonbauer'
42
+
43
+ values = [
44
+ key,
45
+ 'Anton Bauer (1971)',
46
+ 'www.antonbauer.at',
47
+ 'Neufang 42 // 3483 Feuersbrunn',
48
+ '25 ha', ### todo: make sure it will not get matched as tag
49
+ 'tag'
50
+ ]
51
+
52
+ more_attribs = {
53
+ country_id: AT.id
54
+ }
55
+
56
+ wy = Winery.create_or_update_from_values( values, more_attribs )
57
+
58
+ wy2 = Winery.find_by_key!( key )
59
+ assert_equal wy.id, wy2.id
60
+
61
+ assert_equal wy.title, values[1]
62
+ assert_equal wy.country_id, AT.id
63
+ assert_equal wy.country.title, AT.title
64
+ assert_equal wy.web, 'www.antonbauer.at'
65
+ assert_equal wy.address, 'Neufang 42 // 3483 Feuersbrunn'
66
+ end
67
+
68
+
69
+ end # class TestModels
70
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: winedb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2014-03-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
- requirement: &77438490 !ruby/object:Gem::Requirement
16
+ requirement: &71681830 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *77438490
24
+ version_requirements: *71681830
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: worlddb
27
- requirement: &77438010 !ruby/object:Gem::Requirement
27
+ requirement: &71681430 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.7'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *77438010
35
+ version_requirements: *71681430
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: gli
38
- requirement: &77457290 !ruby/object:Gem::Requirement
38
+ requirement: &71681160 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.5.6
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *77457290
46
+ version_requirements: *71681160
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rdoc
49
- requirement: &77456620 !ruby/object:Gem::Requirement
49
+ requirement: &71680880 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '3.10'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *77456620
57
+ version_requirements: *71680880
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: hoe
60
- requirement: &77455830 !ruby/object:Gem::Requirement
60
+ requirement: &71680600 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '3.3'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *77455830
68
+ version_requirements: *71680600
69
69
  description: winedb - wine.db command line tool
70
70
  email: winedb@googlegroups.com
71
71
  executables: []
@@ -78,7 +78,19 @@ files:
78
78
  - README.md
79
79
  - Rakefile
80
80
  - lib/winedb.rb
81
+ - lib/winedb/models/city.rb
82
+ - lib/winedb/models/country.rb
83
+ - lib/winedb/models/forward.rb
84
+ - lib/winedb/models/region.rb
85
+ - lib/winedb/models/tag.rb
86
+ - lib/winedb/models/wine.rb
87
+ - lib/winedb/models/winery.rb
88
+ - lib/winedb/reader.rb
89
+ - lib/winedb/schema.rb
81
90
  - lib/winedb/version.rb
91
+ - test/helper.rb
92
+ - test/test_models.rb
93
+ - .gemtest
82
94
  homepage: https://github.com/geraldb/wine.db.ruby
83
95
  licenses:
84
96
  - Public Domain
@@ -106,4 +118,5 @@ rubygems_version: 1.8.17
106
118
  signing_key:
107
119
  specification_version: 3
108
120
  summary: winedb - wine.db command line tool
109
- test_files: []
121
+ test_files:
122
+ - test/test_models.rb