Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, 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
@cadwallion 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
@cadwallion Updates README about Brewscribe::Document ede6176
View
15 README.md
@@ -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/).
View
5 lib/brewscribe.rb
@@ -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
View
1  lib/brewscribe/conversion.rb
@@ -1,3 +1,4 @@
+require 'date'
module Brewscribe
module Conversion
BOOLEAN_CONV = ->(k) { k == '1' }
View
77 lib/brewscribe/document.rb
@@ -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
View
80 lib/brewscribe/recipe.rb
@@ -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
View
4 spec/brewscribe_spec.rb
@@ -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
View
34 spec/document_spec.rb
@@ -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
View
44 spec/recipe_spec.rb
@@ -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.