winedb 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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