track_parser 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +2 -0
- data/lib/track_parser.rb +5 -0
- data/lib/track_parser/filter_pipeline.rb +21 -0
- data/lib/track_parser/filtered_parts.rb +25 -0
- data/lib/track_parser/filters/featuring_filter.rb +30 -0
- data/lib/track_parser/filters/filter_nodes_mapping.rb +12 -0
- data/lib/track_parser/filters/remix_filter.rb +41 -0
- data/lib/track_parser/nodes/artist_node.rb +14 -0
- data/lib/track_parser/nodes/artists_node.rb +31 -0
- data/lib/track_parser/nodes/base_node.rb +16 -0
- data/lib/track_parser/nodes/empty_node.rb +7 -0
- data/lib/track_parser/nodes/featuring_node.rb +22 -0
- data/lib/track_parser/nodes/name_node.rb +14 -0
- data/lib/track_parser/nodes/remix_node.rb +40 -0
- data/lib/track_parser/nodes/track_node.rb +49 -0
- data/lib/track_parser/nodes/trackname_node.rb +20 -0
- data/lib/track_parser/parser.rb +19 -0
- data/lib/track_parser/processor.rb +53 -0
- data/lib/track_parser/track.rb +49 -0
- data/lib/track_parser/version.rb +3 -0
- data/spec/parser_spec.rb +96 -0
- data/spec/spec_helper.rb +11 -0
- data/track_parser.gemspec +26 -0
- metadata +147 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: 41f48fe39a78f9c5bc0852de5826ba1473fd487e
         | 
| 4 | 
            +
              data.tar.gz: 303e183dc8057a76b3585ea9a048bcb04f6e9c09
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: f2d9a92b145ee0172a4ab131e0542fe5847b7c47217c86a9a5f393bcdc6ebb576e1b3c6727796ddf338dcc7606fc69f807c20d4c17ae0622515cec96c5626b7c
         | 
| 7 | 
            +
              data.tar.gz: cb4bdda3a49365c7360f62ecf4d976e42f4c71d0f78de9db2b67dbada973b63866aef0342789cbcb9d6d78e77bbc87799ade5ca4e6b5616569708f0e66b4b6df
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            Copyright (c) 2014 Alexandre Quintino
         | 
| 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.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            # TrackParser
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Tries to parse the name of a track (e.g. ArtistA - ABC (ArtistB remix)) and extract metadata from it (e.g. artists = ArtistA, track-name = ABC, remixer = ArtistB)
         | 
| 4 | 
            +
            It makes a best effort to extract the metadata by passing the track through a set of rules that most tracks follow. If the track does not follow those rules, the results might not be accurate.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            ## Installation
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            Add this line to your application's Gemfile:
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ```ruby
         | 
| 11 | 
            +
            gem 'track_parser'
         | 
| 12 | 
            +
            ```
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            And then execute:
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                $ bundle
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Or install it yourself as:
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                $ gem install track_parser
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ## Usage
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            ### Simple
         | 
| 25 | 
            +
            ```ruby
         | 
| 26 | 
            +
            require "track_parser"
         | 
| 27 | 
            +
            TrackParser::Parser.do("Derek Marin - We've Been Expecting You - Hreno's Deep Pockets Dub")
         | 
| 28 | 
            +
            => {:artists=>["Derek Marin"], :track_name=>"We've Been Expecting You", :remixer=>"Hreno", :remix_name=>"Deep Pockets Dub"}
         | 
| 29 | 
            +
            ```
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            ### Structured
         | 
| 32 | 
            +
            You might know already the artists. In that case you can use:
         | 
| 33 | 
            +
            ```ruby
         | 
| 34 | 
            +
            require "track_parser"
         | 
| 35 | 
            +
            TrackParser::Parser.do(artists: ["Derek Marin], name: "We've Been Expecting You - Hreno's Deep Pockets Dub")
         | 
| 36 | 
            +
            => {:artists=>["Derek Marin"], :track_name=>"We've Been Expecting You", :remixer=>"Hreno", :remix_name=>"Deep Pockets Dub"}
         | 
| 37 | 
            +
            ```
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            ## Non-exhaustive list of formats supported (for more check the [tests](https://github.com/alexquintino/track_parser/blob/master/spec/parser_spec.rb))
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            * `<artist> - <track name>`
         | 
| 42 | 
            +
            * `<artist> - <track name> [-] (<remixer> Remix|Vocal|Dub|Mix)`
         | 
| 43 | 
            +
            * `<artist> - <track name> (<remixer>'s <remix name>)`
         | 
| 44 | 
            +
            * `<artist> & <artist> - <track name>`
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            ## Contributing
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            1. Fork it ( https://github.com/alexquintino/track_parser/fork )
         | 
| 49 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 50 | 
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         | 
| 51 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 52 | 
            +
            5. Create a new Pull Request
         | 
    
        data/Rakefile
    ADDED
    
    
    
        data/lib/track_parser.rb
    ADDED
    
    
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            require_relative "filters/remix_filter"
         | 
| 2 | 
            +
            require_relative "filters/featuring_filter"
         | 
| 3 | 
            +
            require_relative "filtered_parts"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module TrackParser
         | 
| 6 | 
            +
              class FilterPipeline
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                FILTERS = [RemixFilter, FeaturingFilter] #order matters currently
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def self.filter(text)
         | 
| 11 | 
            +
                  size_last_pass = 0
         | 
| 12 | 
            +
                  filtered = nil
         | 
| 13 | 
            +
                  loop do #make several passes until nothing new is found
         | 
| 14 | 
            +
                    filtered = FILTERS.reduce(FilteredParts.new(text)) { |data, filter_class| filter_class.filter(data) }
         | 
| 15 | 
            +
                    break if filtered.parts.size == size_last_pass
         | 
| 16 | 
            +
                    size_last_pass = filtered.parts.size
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                  return filtered.parts, filtered.text
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module TrackParser
         | 
| 2 | 
            +
              class FilteredParts
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                def initialize(text)
         | 
| 5 | 
            +
                  @remaining = text
         | 
| 6 | 
            +
                  @parts = []
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def text
         | 
| 10 | 
            +
                  @remaining
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def add_part(type, text)
         | 
| 14 | 
            +
                  @parts << {type: type, text: text}
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def remove_text(text)
         | 
| 18 | 
            +
                  @remaining = @remaining.gsub(text, "")
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def parts
         | 
| 22 | 
            +
                  @parts
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module TrackParser
         | 
| 2 | 
            +
              class FeaturingFilter
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                def self.filter(data)
         | 
| 5 | 
            +
                  self.new(data).filter
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(data)
         | 
| 9 | 
            +
                  @data = data
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def filter
         | 
| 13 | 
            +
                  if has_featuring?
         | 
| 14 | 
            +
                    featuring_text = regexp.match(@data.text)[:featuring]
         | 
| 15 | 
            +
                    @data.add_part(:featuring, featuring_text)
         | 
| 16 | 
            +
                    @data.remove_text(featuring_text) #remove featuring artists from trackname
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                  return @data
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def has_featuring?
         | 
| 22 | 
            +
                  !!regexp.match(@data.text)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def regexp
         | 
| 26 | 
            +
                  /(?<featuring>\(?(#{FeaturingNode::VERSIONS_REGEXP})\s.*\)?)/i #find featuring keywords
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            require_relative '../nodes/remix_node'
         | 
| 2 | 
            +
            require_relative '../nodes/featuring_node'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TrackParser
         | 
| 5 | 
            +
              class FilterNodesMapping
         | 
| 6 | 
            +
                FILTERS_NODES_MAPPING = {remix: RemixNode, featuring: FeaturingNode}
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def self.to_nodes(parts)
         | 
| 9 | 
            +
                  parts.map { |part| FILTERS_NODES_MAPPING[part[:type]].new(part[:text])}
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            require_relative "../nodes/remix_node"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module TrackParser
         | 
| 4 | 
            +
              class RemixFilter
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def self.filter(data)
         | 
| 7 | 
            +
                  self.new(data).filter
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def initialize(data)
         | 
| 11 | 
            +
                  @data = data
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def filter
         | 
| 15 | 
            +
                  if has_remix?
         | 
| 16 | 
            +
                    extracted = content.select {|match| !regexp.match(match).nil?}.first #select first that matches a remix
         | 
| 17 | 
            +
                    @data.add_part(:remix, extracted)
         | 
| 18 | 
            +
                    @data.remove_text "(#{extracted})" #remove remix string from
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                  return @data
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def has_remix?
         | 
| 24 | 
            +
                  !!regexp #find remix keywords
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def content
         | 
| 28 | 
            +
                  text = @data.text
         | 
| 29 | 
            +
                  if text =~ /(\(|\))+/
         | 
| 30 | 
            +
                    text.scan(/\((?<content>.*?)\)/).flatten
         | 
| 31 | 
            +
                  else
         | 
| 32 | 
            +
                    [text]
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def regexp
         | 
| 37 | 
            +
                  /(?<remix>.*?\b(#{RemixNode::VERSIONS_REGEXP})+)\b/i
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            require_relative 'artist_node'
         | 
| 2 | 
            +
            require_relative 'base_node'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TrackParser
         | 
| 5 | 
            +
              class ArtistsNode < BaseNode
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(artists)
         | 
| 8 | 
            +
                  super(:artists, artists)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def children
         | 
| 12 | 
            +
                  if @raw.is_a? String
         | 
| 13 | 
            +
                    if multiple?
         | 
| 14 | 
            +
                      @raw.split(regex).map { |capture| ArtistNode.new(capture) }
         | 
| 15 | 
            +
                    else
         | 
| 16 | 
            +
                      [ArtistNode.new(@raw)]
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  else
         | 
| 19 | 
            +
                    @raw.map { |artist| ArtistNode.new(artist) }
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def multiple?
         | 
| 24 | 
            +
                  !!regex.match(@raw)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def regex
         | 
| 28 | 
            +
                  /\s(?:and|&)\s/i
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            require 'ast'
         | 
| 2 | 
            +
            require_relative 'empty_node'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TrackParser
         | 
| 5 | 
            +
              class BaseNode < AST::Node
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.new(text)
         | 
| 8 | 
            +
                  return EmptyNode.new if text.nil? || (text.is_a?(String) && text.strip.empty?)
         | 
| 9 | 
            +
                  super(text)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def initialize(type, text)
         | 
| 13 | 
            +
                  super(type, [], {raw: text})
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            require_relative 'artist_node'
         | 
| 2 | 
            +
            require_relative 'base_node'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TrackParser
         | 
| 5 | 
            +
              class FeaturingNode < BaseNode
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                VERSIONS_REGEXP = ["feat.", "featuring", "ft."].join("|")
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize(artists)
         | 
| 10 | 
            +
                  super(:featuring, artists)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def regexp
         | 
| 14 | 
            +
                  /\(?(#{FeaturingNode::VERSIONS_REGEXP})\s(?<artist>[^\)]*)\)?/i
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def children
         | 
| 18 | 
            +
                  artist = regexp.match(@raw)[:artist]
         | 
| 19 | 
            +
                  [ArtistsNode.new(artist)]
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require_relative 'base_node'
         | 
| 2 | 
            +
            require_relative 'artists_node'
         | 
| 3 | 
            +
            require_relative 'name_node'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module TrackParser
         | 
| 6 | 
            +
              class RemixNode < BaseNode
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                VERSIONS_REGEXP = ["remix", "mix", "vocal", "dub", "rework", "edit", "version", "extended", "club", "original"].join("|")
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def initialize(remix)
         | 
| 11 | 
            +
                  raw = remix.gsub(/(\(|\))/, "") # remove parantheses
         | 
| 12 | 
            +
                  super(:remix, raw)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def children
         | 
| 16 | 
            +
                  if has_remix_name?
         | 
| 17 | 
            +
                    nodes = @raw.split(/(?:'|´)s/)
         | 
| 18 | 
            +
                    [ArtistsNode.new(nodes[0]), NameNode.new(nodes[1])]
         | 
| 19 | 
            +
                  else
         | 
| 20 | 
            +
                    [ArtistsNode.new(remixer), NameNode.new(remix_version)]
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def has_remix_name?
         | 
| 25 | 
            +
                  @raw.include?("'s") || @raw.include?("´s")
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def remixer
         | 
| 29 | 
            +
                  without_version.strip
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def remix_version(remix = @raw)
         | 
| 33 | 
            +
                  remix.scan(/(#{VERSIONS_REGEXP})\b/i).flatten.join(" ")
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def without_version(part = @raw)
         | 
| 37 | 
            +
                  part.gsub(remix_version, "")
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            require_relative 'base_node'
         | 
| 2 | 
            +
            require_relative 'artists_node'
         | 
| 3 | 
            +
            require_relative 'trackname_node'
         | 
| 4 | 
            +
            require_relative 'remix_node'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module TrackParser
         | 
| 7 | 
            +
              class TrackNode < BaseNode
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize(track)
         | 
| 10 | 
            +
                  raw = replace_parentheses(track)
         | 
| 11 | 
            +
                  super(:track, raw)
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def children
         | 
| 15 | 
            +
                  if track_sections.size == 1
         | 
| 16 | 
            +
                    raise UnparseableTrack.new("Don't know how to parse a track without \"-\". Track was:#{@raw}")
         | 
| 17 | 
            +
                  else
         | 
| 18 | 
            +
                    nodes = track_sections[2..-1].map do |track_section|
         | 
| 19 | 
            +
                      parts = FilterPipeline.filter(track_section).first
         | 
| 20 | 
            +
                      FilterNodesMapping.to_nodes(parts)
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                    [ArtistsNode.new(track_sections[0]), TracknameNode.new(track_sections[1])] + nodes.flatten
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def replace_parentheses(text)
         | 
| 27 | 
            +
                  if text.is_a? String
         | 
| 28 | 
            +
                    text.gsub("[","(").gsub("]",")")
         | 
| 29 | 
            +
                  else
         | 
| 30 | 
            +
                    text[:name] = replace_parentheses(text[:name])
         | 
| 31 | 
            +
                    text
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def track_sections
         | 
| 36 | 
            +
                  if @raw.is_a? String
         | 
| 37 | 
            +
                    split_sections(@raw)
         | 
| 38 | 
            +
                  else
         | 
| 39 | 
            +
                    [@raw[:artists]] + split_sections(@raw[:name])
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def split_sections(text)
         | 
| 44 | 
            +
                  text.split(" - ").map(&:strip)
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              class UnparseableTrack < StandardError; end
         | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require_relative 'base_node'
         | 
| 2 | 
            +
            require_relative 'name_node'
         | 
| 3 | 
            +
            require_relative 'remix_node'
         | 
| 4 | 
            +
            require_relative 'featuring_node'
         | 
| 5 | 
            +
            require_relative '../filter_pipeline'
         | 
| 6 | 
            +
            require_relative '../filters/filter_nodes_mapping'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module TrackParser
         | 
| 9 | 
            +
              class TracknameNode < BaseNode
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(trackname)
         | 
| 12 | 
            +
                  super(:trackname, trackname)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def children
         | 
| 16 | 
            +
                  parts, remaining_text = FilterPipeline.filter(@raw)
         | 
| 17 | 
            +
                  [NameNode.new(remaining_text)] + FilterNodesMapping.to_nodes(parts)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require_relative "nodes/track_node"
         | 
| 2 | 
            +
            require_relative "processor"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TrackParser
         | 
| 5 | 
            +
              class Parser
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.do(track)
         | 
| 8 | 
            +
                  self.new(track).parse
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(track)
         | 
| 12 | 
            +
                  @track = TrackNode.new(track)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def parse
         | 
| 16 | 
            +
                  Processor.new.process(@track)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            require "ast"
         | 
| 2 | 
            +
            require_relative "track"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TrackParser
         | 
| 5 | 
            +
              class Processor < AST::Processor
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize
         | 
| 8 | 
            +
                  @track = Track.new
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def on_track(node)
         | 
| 12 | 
            +
                  hash = process_all(node).reduce({}) { |mem, h| mem.merge(h) }
         | 
| 13 | 
            +
                  @track.add_artists(hash[:artists])
         | 
| 14 | 
            +
                  @track
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def on_trackname(node)
         | 
| 18 | 
            +
                  hash = process_all(node).reduce({}) { |mem, h| mem.merge(h) }
         | 
| 19 | 
            +
                  @track.add_name(hash[:name])
         | 
| 20 | 
            +
                  {}
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def on_artists(node)
         | 
| 24 | 
            +
                  artists = process_all(node)
         | 
| 25 | 
            +
                  { artists: artists }
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def on_artist(node)
         | 
| 29 | 
            +
                  node.name
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def on_name(node)
         | 
| 33 | 
            +
                  { name: node.name }
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def on_remix(node)
         | 
| 37 | 
            +
                  hash = process_all(node).reduce({}) { |mem, h| mem.merge(h) }
         | 
| 38 | 
            +
                  @track.add_remixer(hash[:artists])
         | 
| 39 | 
            +
                  @track.add_remix_name(hash[:name])
         | 
| 40 | 
            +
                  {}
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def on_featuring(node)
         | 
| 44 | 
            +
                  artists = process_all(node).first
         | 
| 45 | 
            +
                  @track.add_featuring(artists[:artists])
         | 
| 46 | 
            +
                  {}
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def on_empty(node)
         | 
| 50 | 
            +
                  {}
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            module TrackParser
         | 
| 2 | 
            +
              class Track
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                attr_accessor :artists, :name, :remixer, :remix_name, :featuring
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize(hash = {})
         | 
| 7 | 
            +
                  @artists = hash[:artists]
         | 
| 8 | 
            +
                  @name = hash[:name]
         | 
| 9 | 
            +
                  @remixer = hash[:remixer]
         | 
| 10 | 
            +
                  @remix_name = hash[:remix_name]
         | 
| 11 | 
            +
                  @featuring = hash[:featuring]
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def add_artists(artists)
         | 
| 15 | 
            +
                  @artists = artists
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def add_remixer(remixer)
         | 
| 19 | 
            +
                  return if remixer.nil?
         | 
| 20 | 
            +
                  if @remixer.nil?
         | 
| 21 | 
            +
                    @remixer = remixer
         | 
| 22 | 
            +
                  else
         | 
| 23 | 
            +
                    @remixer.concat(remixer)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def add_remix_name(remix_name)
         | 
| 28 | 
            +
                  return if remix_name.nil?
         | 
| 29 | 
            +
                  if @remix_name.nil?
         | 
| 30 | 
            +
                    @remix_name = remix_name
         | 
| 31 | 
            +
                  else
         | 
| 32 | 
            +
                    @remix_name += " " + remix_name
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def add_name(name)
         | 
| 37 | 
            +
                  @name = name
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def add_featuring(featured_artists)
         | 
| 41 | 
            +
                  @featuring = featured_artists
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def to_s
         | 
| 45 | 
            +
                  "artists='#{@artists}' name='#{@name}' remixer='#{@remixer}' remix_name='#{@remix_name}' featuring='#{featuring}'"
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
            end
         | 
    
        data/spec/parser_spec.rb
    ADDED
    
    | @@ -0,0 +1,96 @@ | |
| 1 | 
            +
            describe TrackParser::Parser do
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              tracks = {
         | 
| 4 | 
            +
                "SIS - Orgsa" =>
         | 
| 5 | 
            +
                  { artists: ["SIS"], name: "Orgsa", remixer: nil, remix_name: nil},
         | 
| 6 | 
            +
                "Roy Davis Jr - About Love (Pezzner Remix)" =>
         | 
| 7 | 
            +
                  { artists: ["Roy Davis Jr"], name: "About Love", remixer: ["Pezzner"], remix_name: "Remix" },
         | 
| 8 | 
            +
                "Julien Perez & Octavio Camino - Parada Maya" =>
         | 
| 9 | 
            +
                  { artists: ["Julien Perez", "Octavio Camino"], name: "Parada Maya", remixer: nil, remix_name: nil},
         | 
| 10 | 
            +
                "Kollektiv Turmstrasse - Ordinary (Lake People's Circle Motive Remix)" =>
         | 
| 11 | 
            +
                  { artists: ["Kollektiv Turmstrasse"], name: "Ordinary", remixer: ["Lake People"], remix_name: "Circle Motive Remix" },
         | 
| 12 | 
            +
                "Derek Marin - We've Been Expecting You - Hreno´s Deep Pockets Dub" =>
         | 
| 13 | 
            +
                  { artists: ["Derek Marin"], name: "We've Been Expecting You", remixer: ["Hreno"], remix_name: "Deep Pockets Dub" },
         | 
| 14 | 
            +
                "Umek & Uto Karem - Crossing the Lines - Original Mix" =>
         | 
| 15 | 
            +
                  { artists: ["Umek", "Uto Karem"], name: "Crossing the Lines", remixer: nil, remix_name: "Original Mix" },
         | 
| 16 | 
            +
                "Noir & Fraser Owen - &U - Mendo and Danny Serrano Remix" =>
         | 
| 17 | 
            +
                  { artists: ["Noir", "Fraser Owen"], name: "&U", remixer: ["Mendo", "Danny Serrano"], remix_name: "Remix"},
         | 
| 18 | 
            +
                "Plastikman - Spastik - Dubfire Rework" =>
         | 
| 19 | 
            +
                  { artists: ["Plastikman"], name: "Spastik", remixer: ["Dubfire"], remix_name: "Rework" },
         | 
| 20 | 
            +
                "Alex Under - El Encuentro - Richie Hawtin Edit" =>
         | 
| 21 | 
            +
                  { artists: ['Alex Under'], name: 'El Encuentro', remixer: ["Richie Hawtin"], remix_name: "Edit" },
         | 
| 22 | 
            +
                "Gorge - Erotic Soul feat. The Writers Poet - Original Mix" =>
         | 
| 23 | 
            +
                  { artists: ["Gorge"], name: "Erotic Soul", featuring: ["The Writers Poet"], remixer: nil, remix_name: "Original Mix"},
         | 
| 24 | 
            +
                "John Talabot & Pional - Destiny (Feat. Pional)" =>
         | 
| 25 | 
            +
                  { artists: ["John Talabot", "Pional"], name: "Destiny", featuring: ["Pional"], remixer: nil, remix_name: nil},
         | 
| 26 | 
            +
                "Ornette - Crazy - Nôze Remix - Extended Club Version" =>
         | 
| 27 | 
            +
                  { artists: ["Ornette"], name: "Crazy", remixer: ["Nôze"], remix_name: "Remix Extended Club Version" },
         | 
| 28 | 
            +
                "2 Guys in Venice & Spiller & Digitalism - Encore - Spiller & 2 Guys In Venice Remix" =>
         | 
| 29 | 
            +
                  { artists: ["2 Guys in Venice", "Spiller", "Digitalism"], name: "Encore", remixer: ["Spiller", "2 Guys In Venice"], remix_name: "Remix" },
         | 
| 30 | 
            +
                "Subb-an - Take You Back (ft. Beckford)" =>
         | 
| 31 | 
            +
                  { artists: ["Subb-an"], name: "Take You Back", featuring: ["Beckford"] },
         | 
| 32 | 
            +
                "Aki Bergen & Pezzner & Terry Grant - Tarareando - Vocal Mix" =>
         | 
| 33 | 
            +
                  { artists: ["Aki Bergen", "Pezzner", "Terry Grant"], name: "Tarareando", remixer: nil, remix_name: "Vocal Mix" },
         | 
| 34 | 
            +
                "Jay Haze & Laila Tov - I Wait For You - Original" =>
         | 
| 35 | 
            +
                  { artists: ["Jay Haze", "Laila Tov"], name: "I Wait For You", remixer: nil, remix_name: "Original"},
         | 
| 36 | 
            +
                "DJ T. - City Life - feat. Cari Golden [Maceo Plex Remix]" =>
         | 
| 37 | 
            +
                  { artists: ["DJ T."], name: "City Life", remixer: ["Maceo Plex"], remix_name: "Remix", featuring: ["Cari Golden"]},
         | 
| 38 | 
            +
                "Fritz Kalkbrenner - Right in the Dark - Henrik Schwarz Remix - Chopstick & Johnjon Edit" =>
         | 
| 39 | 
            +
                  { artists: ["Fritz Kalkbrenner"], name: "Right in the Dark", remixer: ["Henrik Schwarz", "Chopstick", "Johnjon"], remix_name: "Remix Edit"}
         | 
| 40 | 
            +
              }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              tracks_structured = [
         | 
| 43 | 
            +
                {track: { artists: ["Sailor & I"], name: "Tough Love - Aril Brikha Remix" }, result:
         | 
| 44 | 
            +
                  { artists: ["Sailor & I"], name: "Tough Love", remixer: ["Aril Brikha"], remix_name: "Remix"}}
         | 
| 45 | 
            +
              ]
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              let(:parsed_track) { TrackParser::Parser.do(track) }
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              tracks.keys.each do |track|
         | 
| 50 | 
            +
                context "#{track}" do
         | 
| 51 | 
            +
                  let(:track) { track }
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  it "returns the artist correctly" do
         | 
| 54 | 
            +
                    expect(parsed_track.artists).to eq(tracks[track][:artists])
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  it "returns the track name correctly" do
         | 
| 58 | 
            +
                    expect(parsed_track.name).to eq(tracks[track][:name])
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  it "returns the remixer correctly" do
         | 
| 62 | 
            +
                    expect(parsed_track.remixer).to eq(tracks[track][:remixer])
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  it "returns the remix name correctly" do
         | 
| 66 | 
            +
                    expect(parsed_track.remix_name).to eq(tracks[track][:remix_name])
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  it "returns the featured artists correctly" do
         | 
| 70 | 
            +
                    expect(parsed_track.featuring).to eq(tracks[track][:featuring])
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              context "invalid track" do
         | 
| 76 | 
            +
                let(:track) { "Invalid Track" }
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                it "throws an exception when the track doesn't have \"-\"" do
         | 
| 79 | 
            +
                  expect{TrackParser::Parser.do(track)}.to raise_error(TrackParser::UnparseableTrack)
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              context "Hash as input" do
         | 
| 84 | 
            +
                let(:track) { tracks_structured.first[:track] }
         | 
| 85 | 
            +
                let(:result) { tracks_structured.first[:result]}
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                it "returns all the correct info" do
         | 
| 88 | 
            +
                  expect(parsed_track.artists).to eq(result[:artists])
         | 
| 89 | 
            +
                  expect(parsed_track.name).to eq(result[:name])
         | 
| 90 | 
            +
                  expect(parsed_track.remixer).to eq(result[:remixer])
         | 
| 91 | 
            +
                  expect(parsed_track.remix_name).to eq(result[:remix_name])
         | 
| 92 | 
            +
                  expect(parsed_track.featuring).to eq(result[:featuring])
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'track_parser/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name          = "track_parser"
         | 
| 8 | 
            +
              spec.version       = TrackParser::VERSION
         | 
| 9 | 
            +
              spec.authors       = ["Alexandre Quintino"]
         | 
| 10 | 
            +
              spec.email         = ["amsquintino@gmail.com"]
         | 
| 11 | 
            +
              spec.summary       = %q{Tries to parse the name of a track (eg. ArtistA - ABC (ArtistB remix)) and extract metadata from it (eg. artists = ArtistA, track-name = ABC, remixer = ArtistB)}
         | 
| 12 | 
            +
              spec.description   = %q{Tries to parse the name of a track (eg. ArtistA - ABC (ArtistB remix)) and extract metadata from it (eg. artists = ArtistA, track-name = ABC, remixer = ArtistB)}
         | 
| 13 | 
            +
              spec.homepage      = ""
         | 
| 14 | 
            +
              spec.license       = "MIT"
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              spec.files         = `git ls-files -z`.split("\x0")
         | 
| 17 | 
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 18 | 
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 19 | 
            +
              spec.require_paths = ["lib"]
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              spec.add_development_dependency "bundler", "~> 1.6"
         | 
| 22 | 
            +
              spec.add_development_dependency "rake", "~> 10.0"
         | 
| 23 | 
            +
              spec.add_development_dependency "rspec"
         | 
| 24 | 
            +
              spec.add_development_dependency "pry"
         | 
| 25 | 
            +
              spec.add_runtime_dependency "ast"
         | 
| 26 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,147 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: track_parser
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 1.0.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Alexandre Quintino
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2015-03-16 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: bundler
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '1.6'
         | 
| 20 | 
            +
              type: :development
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '1.6'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: rake
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '10.0'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '10.0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: rspec
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - ">="
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - ">="
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: pry
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: ast
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - ">="
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: '0'
         | 
| 76 | 
            +
              type: :runtime
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - ">="
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: '0'
         | 
| 83 | 
            +
            description: Tries to parse the name of a track (eg. ArtistA - ABC (ArtistB remix))
         | 
| 84 | 
            +
              and extract metadata from it (eg. artists = ArtistA, track-name = ABC, remixer =
         | 
| 85 | 
            +
              ArtistB)
         | 
| 86 | 
            +
            email:
         | 
| 87 | 
            +
            - amsquintino@gmail.com
         | 
| 88 | 
            +
            executables: []
         | 
| 89 | 
            +
            extensions: []
         | 
| 90 | 
            +
            extra_rdoc_files: []
         | 
| 91 | 
            +
            files:
         | 
| 92 | 
            +
            - ".gitignore"
         | 
| 93 | 
            +
            - ".rspec"
         | 
| 94 | 
            +
            - Gemfile
         | 
| 95 | 
            +
            - LICENSE.txt
         | 
| 96 | 
            +
            - README.md
         | 
| 97 | 
            +
            - Rakefile
         | 
| 98 | 
            +
            - lib/track_parser.rb
         | 
| 99 | 
            +
            - lib/track_parser/filter_pipeline.rb
         | 
| 100 | 
            +
            - lib/track_parser/filtered_parts.rb
         | 
| 101 | 
            +
            - lib/track_parser/filters/featuring_filter.rb
         | 
| 102 | 
            +
            - lib/track_parser/filters/filter_nodes_mapping.rb
         | 
| 103 | 
            +
            - lib/track_parser/filters/remix_filter.rb
         | 
| 104 | 
            +
            - lib/track_parser/nodes/artist_node.rb
         | 
| 105 | 
            +
            - lib/track_parser/nodes/artists_node.rb
         | 
| 106 | 
            +
            - lib/track_parser/nodes/base_node.rb
         | 
| 107 | 
            +
            - lib/track_parser/nodes/empty_node.rb
         | 
| 108 | 
            +
            - lib/track_parser/nodes/featuring_node.rb
         | 
| 109 | 
            +
            - lib/track_parser/nodes/name_node.rb
         | 
| 110 | 
            +
            - lib/track_parser/nodes/remix_node.rb
         | 
| 111 | 
            +
            - lib/track_parser/nodes/track_node.rb
         | 
| 112 | 
            +
            - lib/track_parser/nodes/trackname_node.rb
         | 
| 113 | 
            +
            - lib/track_parser/parser.rb
         | 
| 114 | 
            +
            - lib/track_parser/processor.rb
         | 
| 115 | 
            +
            - lib/track_parser/track.rb
         | 
| 116 | 
            +
            - lib/track_parser/version.rb
         | 
| 117 | 
            +
            - spec/parser_spec.rb
         | 
| 118 | 
            +
            - spec/spec_helper.rb
         | 
| 119 | 
            +
            - track_parser.gemspec
         | 
| 120 | 
            +
            homepage: ''
         | 
| 121 | 
            +
            licenses:
         | 
| 122 | 
            +
            - MIT
         | 
| 123 | 
            +
            metadata: {}
         | 
| 124 | 
            +
            post_install_message: 
         | 
| 125 | 
            +
            rdoc_options: []
         | 
| 126 | 
            +
            require_paths:
         | 
| 127 | 
            +
            - lib
         | 
| 128 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 129 | 
            +
              requirements:
         | 
| 130 | 
            +
              - - ">="
         | 
| 131 | 
            +
                - !ruby/object:Gem::Version
         | 
| 132 | 
            +
                  version: '0'
         | 
| 133 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 134 | 
            +
              requirements:
         | 
| 135 | 
            +
              - - ">="
         | 
| 136 | 
            +
                - !ruby/object:Gem::Version
         | 
| 137 | 
            +
                  version: '0'
         | 
| 138 | 
            +
            requirements: []
         | 
| 139 | 
            +
            rubyforge_project: 
         | 
| 140 | 
            +
            rubygems_version: 2.4.5
         | 
| 141 | 
            +
            signing_key: 
         | 
| 142 | 
            +
            specification_version: 4
         | 
| 143 | 
            +
            summary: Tries to parse the name of a track (eg. ArtistA - ABC (ArtistB remix)) and
         | 
| 144 | 
            +
              extract metadata from it (eg. artists = ArtistA, track-name = ABC, remixer = ArtistB)
         | 
| 145 | 
            +
            test_files:
         | 
| 146 | 
            +
            - spec/parser_spec.rb
         | 
| 147 | 
            +
            - spec/spec_helper.rb
         |