Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base: f864cb142f
...
compare: ede6176ee1
  • 2 commits
  • 8 files changed
  • 0 commit comments
  • 1 contributor
Commits on Apr 06, 2012
Andrew Nordman Adds Document, refactors Recipe heavily
Since .bsmx files can contain an infinite number of recipes, along with other types
of data, a .bsmx is now translating into a Brewscribe::Document.  Brewscribe::Document
will contain the parsed data objects, including recipes.  This means that Document is
focusing on the XML->Hash conversion, and subsequent classes are dealing with the
resulting Hash that Document has generated.

Additionally, Brewscribe#import is now syntactic suger for Brewscribe::Document.new
8309f4f
Andrew Nordman Updates README about Brewscribe::Document ede6176
15 README.md
View
@@ -9,8 +9,9 @@ Brewscribe is a Beersmith2 (.bsmx) file parser.
## Usage
To start, you can import your .bsmx file with `Brewscribe.import(file)` where file
-is any object that responds to `#read`. This will return an array of Brewscribe::Recipe
-objects. You now have a parsed version of the recipe files.
+is any object that responds to `#read`. This will return a `Brewscribe::Document`
+object, containing all the parsed information within the file. Currently, only Recipe
+objects will be parsed.
By default, Brewscribe will set a text property for each attribute of the recipe, and
if it has a parser object it will attempt to further parse the data.
@@ -18,7 +19,8 @@ if it has a parser object it will attempt to further parse the data.
An example of this is found in `Brewscribe::IngredientList`:
```
-recipe = Brewscribe.import File.read './spec/support/recipe.bsmx'
+document = Brewscribe.import File.read './spec/support/recipe.bsmx'
+recipe = document.recipes.first
recipe.ingredients.class # => Brewscribe::IngredientList
recipe.ingredients.grains.class # => Array
recipe.ingredients.grains.first.class # => Brewscribe::Grain
@@ -35,6 +37,13 @@ I <3 Contributions.
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
+## TODO
+
+* More detailed Brewscribe::Recipe parsing. Mash info especially
+* Beersmith Style parsing
+* Writing back to .bsmx
+* More documentation
+
## Author
Created by [Andrew Nordman](https://github.com/cadwallion/).
5 lib/brewscribe.rb
View
@@ -1,4 +1,5 @@
-require "brewscribe/version"
+require 'brewscribe/version'
+require 'brewscribe/document'
require 'brewscribe/recipe'
require 'brewscribe/ingredient_list'
require 'brewscribe/conversion'
@@ -6,6 +7,6 @@
module Brewscribe
def self.import file
data = file.read
- Recipe.new(data)
+ Document.new(data: data)
end
end
1  lib/brewscribe/conversion.rb
View
@@ -1,3 +1,4 @@
+require 'date'
module Brewscribe
module Conversion
BOOLEAN_CONV = ->(k) { k == '1' }
77 lib/brewscribe/document.rb
View
@@ -0,0 +1,77 @@
+module Brewscribe
+ class Document
+ attr_reader :recipes, :raw_data, :hash
+
+ def initialize options = {}
+ @recipes = []
+
+ if options[:file]
+ @raw_data = File.read options[:file]
+ elsif options[:data]
+ @raw_data = options[:data]
+ end
+
+ parse_data
+ end
+
+ def parse_data
+ @xml = Nokogiri::XML(@raw_data).xpath('/Selections/Data')
+ @hash = xml_node_to_hash @xml.first
+
+ if @hash[:recipe].class == Hash
+ parse_recipes [@hash[:recipe]]
+ else
+ parse_recipes Array @hash[:recipe]
+ end
+
+ self
+ end
+
+ def parse_recipes recipes
+ recipes.each do |recipe_hash|
+ @recipes << Recipe.new(recipe_hash)
+ end
+ end
+
+ def xml_node_to_hash node
+ if node.element?
+ if node.children.size > 0
+ result_hash = {}
+
+ node.children.each do |child|
+ result = xml_node_to_hash child
+ property = clean_key child.name
+ key = property.to_sym
+
+ if child.name == 'text'
+ return result if !child.next && !child.previous
+ elsif result_hash[key]
+ if result_hash[key].is_a? Array
+ result_hash[key] << result
+ else
+ result_hash[key] = [result_hash[key]] << result
+ end
+ else
+ result_hash[key] = result
+ end
+ end
+
+ return result_hash
+ else
+ return nil
+ end
+ else
+ return node.content.to_s
+ end
+ end
+
+ def clean_key key
+ extracted = key.to_s.match(/(F_(\w{1,2}_)?)?(_MOD_|.+)/)[3]
+ if extracted == '_MOD_'
+ return 'last_modified'
+ else
+ extracted.downcase
+ end
+ end
+ end
+end
80 lib/brewscribe/recipe.rb
View
@@ -3,74 +3,22 @@
module Brewscribe
class Recipe
attr_reader :raw_data, :hash
-
- def initialize raw_data
- @raw_data = raw_data
-
- parse_raw_data
- end
-
- def parse_raw_data
- @xml = Nokogiri::XML(@raw_data).xpath('/Selections/Data/Recipe')
- @hash = xml_node_to_hash(@xml.first)
-
- create_recipe_accessors
- parse_ingredients
- end
-
- def create_recipe_accessors
- @hash.keys.each do |key|
- self.class.module_eval do
- attr_accessor key
- end
-
- self.send "#{key}=", @hash[key]
+ attr_accessor :age, :asst_brewer, :base_grain, :boil_vol_measured, :brewer,
+ :carb, :carb_vols, :color_adj_string, :date, :description, :desired_color,
+ :desired_ibu, :desired_og, :equipment, :fg_measured, :final_vol_measured,
+ :image, :image_x, :image_y, :include_starter, :ingredients, :inv_date,
+ :last_modified, :locked, :mash, :mash_ph, :name, :notes, :og_boil_measured,
+ :og_measured, :og_primary, :og_secondary, :old_boil_vol, :old_efficiency,
+ :old_type, :old_vol, :rating, :raw_data, :rebalance_scale, :running_gravity,
+ :runoff_ph, :starter_size, :stir_plate, :style, :type, :version,
+ :volume_measured
+
+ def initialize data = {}
+ data.keys.each do |key|
+ self.send "#{key}=", data[key]
end
- end
-
- def clean_key key
- extracted = key.to_s.match(/(F_(\w{1,2}_)?)?(_MOD_|.+)/)[3]
- if extracted == '_MOD_'
- return 'last_modified'
- else
- extracted.downcase
- end
- end
-
- def parse_ingredients
- self.ingredients = IngredientList.from_data(self.ingredients[:data])
- end
-
- def xml_node_to_hash node
- if node.element?
- if node.children.size > 0
- result_hash = {}
-
- node.children.each do |child|
- result = xml_node_to_hash child
- property = clean_key child.name
- key = property.to_sym
-
- if child.name == 'text'
- return result if !child.next && !child.previous
- elsif result_hash[key]
- if result_hash[key].is_a? Array
- result_hash[key] << result
- else
- result_hash[key] = [result_hash[key]] << result
- end
- else
- result_hash[key] = result
- end
- end
- return result_hash
- else
- return nil
- end
- else
- return node.content.to_s
- end
+ self.ingredients = IngredientList.from_data self.ingredients[:data]
end
end
end
4 spec/brewscribe_spec.rb
View
@@ -14,11 +14,11 @@
Brewscribe.import(file)
end
- it 'should return a Recipe object' do
+ it 'should return a Document object' do
file = double()
file.stub(:read)
recipe = Brewscribe.import(file)
- recipe.should be_a(Brewscribe::Recipe)
+ recipe.should be_a(Brewscribe::Document)
end
end
end
34 spec/document_spec.rb
View
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe Brewscribe::Document do
+ let(:file) { File.open(File.dirname(__FILE__) + '/support/recipe.bsmx', 'r') }
+ subject { Brewscribe::Document.new file: file }
+
+ describe '#parse' do
+ it 'should add a Recipe to recipes when a Recipe entry is found' do
+ subject.recipes.should have(0).recipes
+ hash = subject.parse
+ subject.recipes.should have(1).recipe
+ subject.recipes[0].should be_a Brewscribe::Recipe
+ end
+ end
+
+ describe '#clean_key' do
+ it 'converts an ugly key into something more readable' do
+ subject.clean_key("F_Y_BREW_DATE").should == 'brew_date'
+ end
+
+ it 'converts _MOD_ key to last_modified' do
+ subject.clean_key('_MOD_').should == 'last_modified'
+ end
+ end
+
+ describe '#xml_node_to_hash' do
+ it 'converts xml to a corresponding hash' do
+ xml = Nokogiri::XML('<foo><bar><baz>1</baz></bar><bazaar>2</bazaar></foo>')
+ actual = subject.xml_node_to_hash(xml.root)
+ expected = { bar: { baz: '1' }, bazaar: '2' }
+ actual.should == expected
+ end
+ end
+end
44 spec/recipe_spec.rb
View
@@ -1,43 +1,19 @@
require 'spec_helper'
describe Brewscribe::Recipe do
- let(:recipe_file) { File.open(File.dirname(__FILE__) + '/support/recipe.bsmx', 'r') }
- subject { Brewscribe::Recipe.new(recipe_file.read) }
- describe '#parse_raw_data' do
- it 'should convert the recipe data into properties' do
- subject.brewer.should == 'CadBrew'
- end
-
- it 'should return a hash for nested recipe attributes' do
- subject.equipment.should be_a Hash
- subject.equipment[:name].should be_a String
- end
- end
-
- describe '#clean_key' do
- it 'converts an ugly key into something more readable' do
- subject.clean_key("F_Y_BREW_DATE").should == 'brew_date'
- end
-
- it 'converts _MOD_ key to last_modified' do
- subject.clean_key('_MOD_').should == 'last_modified'
- end
+ let(:recipe_file) { File.read(File.dirname(__FILE__) + '/support/recipe.bsmx') }
+ let(:data) { Brewscribe::Document.new(data: recipe_file).parse.hash[:recipe] }
+ subject { Brewscribe::Recipe.new(data) }
+ it 'should convert the recipe data into properties' do
+ subject.brewer.should == 'CadBrew'
end
- describe '#xml_node_to_hash' do
- it 'converts xml to a corresponding hash' do
- xml = Nokogiri::XML('<foo><bar><baz>1</baz></bar><bazaar>2</bazaar></foo>')
- actual = subject.xml_node_to_hash(xml.root)
- expected = { bar: { baz: '1' }, bazaar: '2' }
- actual.should == expected
- end
+ it 'should return a hash for nested recipe attributes' do
+ subject.equipment.should be_a Hash
+ subject.equipment[:name].should be_a String
end
- describe '#parse_ingredients' do
- it 'should create a Brewscribe::IngredientList object' do
- subject.ingredients = subject.hash[:ingredients]
- subject.parse_ingredients
- subject.ingredients.should be_a Brewscribe::IngredientList
- end
+ it 'should contain an IngredientsList' do
+ subject.ingredients.should be_a Brewscribe::IngredientList
end
end

No commit comments for this range

Something went wrong with that request. Please try again.