├── .gitignore ├── .rspec ├── Gemfile ├── Guardfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── lib └── psd │ ├── enginedata.rb │ └── enginedata │ ├── document_helpers.rb │ ├── errors.rb │ ├── instruction.rb │ ├── instructions │ ├── boolean.rb │ ├── hash_end.rb │ ├── hash_start.rb │ ├── multi_line_array_end.rb │ ├── multi_line_array_start.rb │ ├── noop.rb │ ├── number.rb │ ├── number_with_decimal.rb │ ├── property.rb │ ├── property_with_data.rb │ ├── single_line_array.rb │ └── string.rb │ ├── node.rb │ ├── text.rb │ └── version.rb ├── psd-enginedata.gemspec └── spec ├── files ├── enginedata └── source.psd ├── parser_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | .DS_Store 19 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format progress 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # A sample Guardfile 2 | # More info at https://github.com/guard/guard#readme 3 | 4 | guard :rspec do 5 | watch(%r{^spec/.+_spec\.rb$}) 6 | watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } 7 | watch('spec/spec_helper.rb') { "spec" } 8 | end 9 | 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 LayerVault 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PSD EngineData 2 | 3 | Adobe thought it would be cool to create their own markup language for text data embedded within a Photoshop document. I've taken the liberty of calling it EngineData since that is the name used in the descriptor embedded within PSD files. This is a general purpose parser for that data. 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | gem 'psd-enginedata' 10 | 11 | And then execute: 12 | 13 | $ bundle 14 | 15 | Or install it yourself as: 16 | 17 | $ gem install psd-enginedata 18 | 19 | ## Usage 20 | 21 | ``` ruby 22 | # From File 23 | parser = PSD::EngineData.load('path/to/file') 24 | 25 | # From string 26 | parser = PSD::EngineData.new(text) 27 | 28 | # Parse it 29 | parser.parse! 30 | 31 | # Use it 32 | puts parser.result.Editor.Text 33 | ``` 34 | 35 | ## File Spec 36 | 37 | The EngineData format uses certain characters to denote various data types. All newlines are denoted with a UNIX newline (\n) and it is not indentation-aware (although it seems to be stored with pretty indentation in the PSD file). 38 | 39 | ``` 40 | << 41 | /EngineDict 42 | << 43 | /Editor 44 | << 45 | /Text (˛ˇMake a change and save.) 46 | >> 47 | >> 48 | /Font 49 | << 50 | /Name (˛ˇHelveticaNeue-Light) 51 | /FillColor 52 | << 53 | /Type 1 54 | /Values [ 1.0 0.0 0.0 0.0 ] 55 | >> 56 | /StyleSheetSet [ 57 | << 58 | /Name (˛ˇNormal RGB) 59 | >> 60 | ] 61 | >> 62 | >> 63 | ``` 64 | 65 | There are 6 data types available to use: 66 | 67 | * Dictionary/Hash 68 | * Array (single or multi-line) 69 | * Float 70 | * Integer 71 | * String 72 | * Boolean 73 | 74 | Altogether we have a non-turing complete markup language with some interesting quirks that was written in 1998 with the release of Photoshop 5.0 since it included the ability to edit text areas after they were created (before that, they were rasterized immediately). 75 | 76 | ### Property Names 77 | 78 | Property names are started with a `/` followed by an alphanumeric word. The property value either comes after a space or a new line. 79 | 80 | ### Dictionaries/Hashes 81 | 82 | Dictionaries are denoted by a property name (unless at the root), followed by a new line and the `<<` instruction. The end of a dictionary is denoted by the `>>` instruction. 83 | 84 | A dictionary can contain any type of data including more dictionaries for nesting purposes. All values within a dictionary must have a property followed by a value of some kind. 85 | 86 | ### Arrays 87 | 88 | Arrays come in two flavors: single-line or multi-line. Both are denoted by square brackets `[ ]`. 89 | 90 | Single-line arrays can only hold number values (doubles or integers). While it wouldn't be out of the question for it to hold string or boolean values, this does not seem to appear in any tested Photoshop documents so we're going to assume it's not a part of the specification. Values in single-line arrays are **space delimited**. There seems to be a space between the opening and closing square brackets and the data, but we assume it's optional. 91 | 92 | Multi-line arrays can contain any type of data. Values in multi-line arrays are newline-denoted. The opening bracket for multi-line arrays must occur on the same line as the property to which it belongs. 93 | 94 | ### Floats/Integers 95 | 96 | Basically, numbers can be expressed with or without a decimal point. Floats are of the form `1.76`, but the non-fractional digits to the left of the decimal point are optional. Integers are just numbers with no commas or decimal points. 97 | 98 | ### Strings 99 | 100 | Strings are delimited by parentheses with a cedilla-breve (thanks [Rob](http://github.com/robgrant) for the terminology) at the start of the string. Since operations are UNIX newline (\n) delimited within the document, new lines in strings are denoted by carriage returns (\r). 101 | 102 | ### Booleans 103 | 104 | Booleans are simply denoted by `true` or `false`. Cool. 105 | 106 | ## Contributing 107 | 108 | 1. Fork it 109 | 2. Create your feature branch (`git checkout -b my-new-feature`) 110 | 3. Commit your changes (`git commit -am 'Add some feature'`) 111 | 4. Push to the branch (`git push origin my-new-feature`) 112 | 5. Create new Pull Request 113 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /lib/psd/enginedata.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | require 'hashie' 3 | 4 | dir_root = File.dirname(File.absolute_path(__FILE__)) + '/enginedata' 5 | [ 6 | '/instructions/*', 7 | '/exporters/*', 8 | '/**/*' 9 | ].each do |path| 10 | Dir.glob(dir_root + path) { |file| require file if File.file?(file) } 11 | end 12 | 13 | class PSD 14 | # General purpose parser for the text data markup present within PSD documents. 15 | class EngineData 16 | attr_reader :text 17 | attr_accessor :property_stack, :node_stack, :property, :node 18 | alias :result :node 19 | 20 | include DocumentHelpers 21 | 22 | # All of the instructions as defined by the EngineData spec. 23 | INSTRUCTIONS = [ 24 | Instruction::HashStart, 25 | Instruction::HashEnd, 26 | Instruction::SingleLineArray, 27 | Instruction::MultiLineArrayStart, 28 | Instruction::MultiLineArrayEnd, 29 | Instruction::Property, 30 | Instruction::PropertyWithData, 31 | Instruction::String, 32 | Instruction::NumberWithDecimal, 33 | Instruction::Number, 34 | Instruction::Boolean, 35 | Instruction::Noop 36 | ] 37 | 38 | # Read a file containing EngineData markup and initialize a new instance. 39 | def self.load(file) 40 | self.new File.new(file, 'rb').read 41 | end 42 | 43 | # Create a new Text instance and initialize our parsing stacks. 44 | def initialize(text) 45 | @text = Text.new(text) 46 | 47 | @property_stack = [] 48 | @node_stack = [] 49 | 50 | @property = :root 51 | @node = nil 52 | 53 | @parsed = false 54 | end 55 | 56 | # Parses the full document. 57 | def parse! 58 | return if parsed? 59 | 60 | while true 61 | line = @text.current 62 | @parsed = true and return if line.nil? 63 | 64 | parse_tokens(line) 65 | @text.next! 66 | end 67 | end 68 | 69 | # Has the document been parsed yet? 70 | def parsed? 71 | @parsed 72 | end 73 | 74 | # Go through each instruction until a token match is found, then parse the 75 | # matches. 76 | def parse_tokens(text) 77 | INSTRUCTIONS.each do |inst| 78 | match = inst.match(text) 79 | return inst.new(self, text).execute! if match 80 | end 81 | 82 | # This is a hack for the Japanese character rules that the format embeds 83 | match = Instruction::String.match(text + @text.next) 84 | if match 85 | text += @text.next! 86 | return Instruction::String.new(self, text).execute! 87 | end 88 | 89 | raise TokenNotFound.new("Text = #{text.dump}, Line = #{@text.line + 1}") 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /lib/psd/enginedata/document_helpers.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | # A collection of helper methods that are used to manipulate the internal 5 | # data structure while parsing. 6 | module DocumentHelpers 7 | # Pushes a property and node onto the parsing stack. 8 | def stack_push(property = nil, node = nil) 9 | node = @node if node.nil? 10 | property = @property if property.nil? 11 | 12 | @node_stack.push node 13 | @property_stack.push property 14 | end 15 | 16 | # Pops a property and node from the parsing stack 17 | def stack_pop 18 | return @property_stack.pop, @node_stack.pop 19 | end 20 | 21 | # Sets the current active node 22 | def set_node(node) 23 | @node = node 24 | end 25 | 26 | # Creates a new node 27 | def reset_node 28 | @node = Node.new 29 | end 30 | 31 | # Sets the current active property 32 | def set_property(property = nil) 33 | @property = property 34 | end 35 | 36 | # Updates a node with a given property and child node. 37 | def update_node(property, node) 38 | if node.is_a?(PSD::EngineData::Node) 39 | node[property] = @node 40 | elsif node.is_a?(Array) 41 | node.push @node 42 | end 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/psd/enginedata/errors.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData #:nodoc: 4 | class TokenNotFound < StandardError; end 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instruction.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | # A single instruction as defined by the EngineData spec. 5 | class Instruction 6 | # The regex for the token, defaulted to nil. Override this. 7 | def self.token; end 8 | 9 | # Checks to see if the given text is a match for this token. 10 | def self.match(text) 11 | begin 12 | token.match(text) 13 | rescue Encoding::CompatibilityError 14 | nil 15 | end 16 | end 17 | 18 | # Stores a reference to the EngineData document and the current 19 | # String being parsed. 20 | def initialize(document, text) 21 | @document = document 22 | @text = text 23 | end 24 | 25 | # Returns the regex match to the current string. 26 | def match 27 | self.class.match @text 28 | end 29 | 30 | # Once matched, we execute the instruction and apply the changes 31 | # to the parsed data. 32 | def execute!; end 33 | 34 | def method_missing(method, *args, &block) 35 | if @document.respond_to?(method) 36 | return @document.send(method, *args) 37 | end 38 | 39 | super 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/boolean.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class Boolean < Instruction 6 | def self.token; /^(true|false)$/; end 7 | 8 | def execute! 9 | match[1] == 'true' ? true : false 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/hash_end.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class HashEnd < Instruction 6 | def self.token; /^>>$/; end 7 | 8 | def execute! 9 | property, node = stack_pop 10 | return if node.nil? 11 | 12 | update_node property, node 13 | set_node node 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/hash_start.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class HashStart < Instruction 6 | def self.token; /^<<$/; end 7 | 8 | def execute! 9 | stack_push 10 | reset_node 11 | set_property 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/multi_line_array_end.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class MultiLineArrayEnd < Instruction 6 | def self.token; /^\]$/; end 7 | 8 | def execute! 9 | property, node = stack_pop 10 | update_node(property, node) 11 | set_node node 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/multi_line_array_start.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class MultiLineArrayStart < Instruction 6 | def self.token; /^\/(\w+) \[$/; end 7 | 8 | def execute! 9 | stack_push match[1] 10 | set_node [] 11 | set_property 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/noop.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class Noop < Instruction 6 | def self.token; /^$/; end 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/number.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class Number < Instruction 6 | def self.token; /^(-?\d+)$/; end 7 | 8 | def execute! 9 | match[1].to_i 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/number_with_decimal.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class NumberWithDecimal < Instruction 6 | def self.token; /^(-?\d*)\.(\d+)$/; end 7 | 8 | def execute! 9 | "#{match[1]}.#{match[2]}".to_f 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/property.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class Property < Instruction 6 | def self.token; /^\/([A-Z0-9]+)$/i; end 7 | 8 | def execute! 9 | set_property match[1] 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/property_with_data.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class PropertyWithData < Instruction 6 | def self.token; /^\/([A-Z0-9]+) (.*)$/i; end 7 | 8 | def execute! 9 | set_property match[1] 10 | data = parse_tokens match[2] 11 | 12 | if node.is_a?(PSD::EngineData::Node) 13 | node[property] = data 14 | elsif node.is_a?(Array) 15 | node.push data 16 | end 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/single_line_array.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class SingleLineArray < Instruction 6 | def self.token; /^\[(.*)\]$/; end 7 | 8 | def execute! 9 | items = match[1].strip.split(" ") 10 | data = [] 11 | 12 | items.each do |item| 13 | data << parse_tokens(item) 14 | end 15 | 16 | return data 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/psd/enginedata/instructions/string.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | class Instruction 5 | class String < Instruction 6 | def self.token; Regexp.new('^\(\xFE\xFF(.*)\)$'.force_encoding('binary')); end 7 | 8 | def execute! 9 | data = self.class.token.match( 10 | @text.force_encoding('binary') 11 | )[1] 12 | 13 | begin 14 | data 15 | .force_encoding('UTF-16BE') 16 | .encode('UTF-8', 'UTF-16BE', universal_newline: true) 17 | .strip 18 | rescue 19 | data 20 | end 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/psd/enginedata/node.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | # Represents a single node in the parsing tree. Extended with Hashie methods 5 | # to make data access easier. 6 | class Node < Hash 7 | include Hashie::Extensions::MergeInitializer 8 | include Hashie::Extensions::MethodAccess 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/psd/enginedata/text.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | # Sanitizes and helps with access to the document text. 5 | class Text 6 | # The current document split by newlines into an array. 7 | attr_reader :text 8 | 9 | # The current line number in the document. 10 | attr_accessor :line 11 | 12 | # Stores the document as a newline-split array and initializes 13 | # the current line to 0. 14 | def initialize(text) 15 | @text = text.split("\n") 16 | @line = 0 17 | end 18 | 19 | # Returns the current line stripped of any tabs and padding. 20 | def current 21 | return nil if at_end? 22 | @text[@line].gsub(/\t/, "").strip 23 | end 24 | 25 | # Are we at the end of the document? 26 | def at_end? 27 | @text[@line].nil? 28 | end 29 | 30 | # Moves the line pointer to the next line and returns it. 31 | def next! 32 | @line += 1 33 | current 34 | end 35 | 36 | # Peeks at the next line in the document without moving the 37 | # line pointer. 38 | def next 39 | @text[@line + 1] 40 | end 41 | 42 | # Returns the number of lines in the document. 43 | def length 44 | @text.length 45 | end 46 | alias :size :length 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/psd/enginedata/version.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class PSD 3 | class EngineData 4 | VERSION = "1.1.1" 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /psd-enginedata.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'psd/enginedata/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "psd-enginedata" 8 | spec.version = PSD::EngineData::VERSION 9 | spec.authors = ["Ryan LeFevre"] 10 | spec.email = ["meltingice8917@gmail.com"] 11 | spec.description = %q{Parser for the markup format used in the PSD file format} 12 | spec.summary = %q{Parser for the markup format used in the PSD file format} 13 | spec.homepage = "http://cosmos.layervault.com/psdrb.html" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files`.split($/) 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = Dir.glob("spec/**/*") 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_dependency 'hashie' 22 | 23 | spec.add_development_dependency "bundler", "~> 1.3" 24 | spec.add_development_dependency "rake" 25 | spec.add_development_dependency "rspec" 26 | spec.add_development_dependency "guard" 27 | spec.add_development_dependency "guard-rspec" 28 | spec.add_development_dependency "rb-fsevent", "~> 0.9" 29 | end 30 | -------------------------------------------------------------------------------- /spec/files/enginedata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/layervault/psd-enginedata/48220c6b1ba8bb09b0ad29b5d565dfae24310f56/spec/files/enginedata -------------------------------------------------------------------------------- /spec/files/source.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/layervault/psd-enginedata/48220c6b1ba8bb09b0ad29b5d565dfae24310f56/spec/files/source.psd -------------------------------------------------------------------------------- /spec/parser_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | require 'spec_helper' 3 | 4 | describe 'Parser' do 5 | let(:parser) { PSD::EngineData.load('spec/files/enginedata') } 6 | 7 | it "is ready to parse" do 8 | expect(parser.text).to_not be_nil 9 | expect(parser).to_not be_parsed 10 | end 11 | 12 | it "does not error when parsing" do 13 | parser.parse! 14 | expect(parser).to be_parsed 15 | end 16 | 17 | describe "result data" do 18 | before(:each) do 19 | parser.parse! 20 | end 21 | 22 | it "contains the proper data" do 23 | expect(parser.result.EngineDict.Editor.Text).to eq("PSD · Enginedata") 24 | end 25 | 26 | it "parses font data" do 27 | names = parser.result.ResourceDict.FontSet.map(&:Name) 28 | expect(names).to include 'MyriadPro-Regular' 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | require './lib/psd/enginedata' 3 | 4 | RSpec.configure do |config| 5 | unless ENV['CIRCLECI'] 6 | config.filter_run focus: true 7 | end 8 | 9 | config.treat_symbols_as_metadata_keys_with_true_values = true 10 | config.run_all_when_everything_filtered = true 11 | 12 | # Run specs in random order to surface order dependencies. If you find an 13 | # order dependency and want to debug it, you can fix the order by providing 14 | # the seed, which is printed after each run. 15 | # --seed 1234 16 | config.order = 'random' 17 | end 18 | --------------------------------------------------------------------------------