diff --git a/src/bindings/ruby/README.md b/src/bindings/ruby/README.md
index 5ed26aebf351da13b7687480d784ce2e7d6843fe..1876fc7317823d0234c6157b9128c101e8d1b90c 100644
--- a/src/bindings/ruby/README.md
+++ b/src/bindings/ruby/README.md
@@ -47,7 +47,7 @@ Also possible:
 ```ruby
 parser = Hammer::ParserBuilder.new
   .token('Hello ')
-  .choice(Hammer::Parser::Token.new('Mom'), Hammer::Parser::Token.new('Dad'))
+  .choice(Hammer::Parser.token('Mom'), Hammer::Parser.token('Dad'))
   .token('!')
   .build
 ```
@@ -56,7 +56,7 @@ More like hammer in C:
 
 ```ruby
 h = Hammer::Parser
-parser = h.sequence(h.token('Hello'), h.choice(h.token('Mom'), h.token('Dad')), h.token('!'))
+parser = h.sequence(h.token('Hello '), h.choice(h.token('Mom'), h.token('Dad')), h.token('!'))
 ```
 
 ### Parsing
diff --git a/src/bindings/ruby/lib/hammer.rb b/src/bindings/ruby/lib/hammer.rb
index 2699d96f982a5f1e3dccf078d0567963f3e24ce7..0f10ab182f82755f0488382d8e480967c336fff6 100644
--- a/src/bindings/ruby/lib/hammer.rb
+++ b/src/bindings/ruby/lib/hammer.rb
@@ -32,16 +32,6 @@ if parser
   p parser.parse 'blah'
 end
 
-parser = Hammer::Parser::Sequence.new(
-  Hammer::Parser::Token.new('Hello '),
-  Hammer::Parser::Choice.new(
-    Hammer::Parser::Token.new('Mom'),
-    Hammer::Parser::Token.new('Dad')
-  ),
-  Hammer::Parser::Token.new('!')
-)
-p parser.parse 'Hello Mom!'
-
 parser = Hammer::Parser.build {
   token 'Hello '
   choice {
@@ -54,12 +44,11 @@ p parser.parse 'Hello Mom!'
 
 parser = Hammer::ParserBuilder.new
   .token('Hello ')
-  .choice(Hammer::Parser::Token.new('Mom'), Hammer::Parser::Token.new('Dad'))
+  .choice(Hammer::Parser.token('Mom'), Hammer::Parser.token('Dad'))
   .token('!')
   .build
 p parser.parse 'Hello Mom!'
 
-# not yet working
-#h = Hammer::Parser
-#parser = h.sequence(h.token('Hello'), h.choice(h.token('Mom'), h.token('Dad')), h.token('!'))
-#p parser.parse 'Hello Mom!'
+h = Hammer::Parser
+parser = h.sequence(h.token('Hello '), h.choice(h.token('Mom'), h.token('Dad')), h.token('!'))
+p parser.parse 'Hello Mom!'
diff --git a/src/bindings/ruby/lib/hammer/parser.rb b/src/bindings/ruby/lib/hammer/parser.rb
index a7b75e273a820963ce0132270b8ad049f67f2e4d..5d1e8e57c1a0c6704608b4a9336fb1e624d6b48f 100644
--- a/src/bindings/ruby/lib/hammer/parser.rb
+++ b/src/bindings/ruby/lib/hammer/parser.rb
@@ -14,95 +14,51 @@ module Hammer
       !result.null?
     end
 
-    class Token < Parser
-      def initialize(string)
-        @h_parser = Hammer::Internal.h_token(string, string.length)
-      end
+    def self.token(string)
+        h_parser = Hammer::Internal.h_token(string, string.length)
+
+        parser = Hammer::Parser.new
+        parser.instance_variable_set :@h_parser, h_parser
+        return parser
     end
 
-    class Ch < Parser
-      def initialize(char)
+    def self.ch(char)
         # TODO: Really? Should probably accept Fixnum in appropriate range
-        # Also, char.ord gives unexptected results if you pass e.g. Japanese characters: '今'.ord == 20170; Hammer::Parser::Ch.new('今').parse(202.chr) == true
+        # Also, char.ord gives unexpected results if you pass e.g. Japanese characters: '今'.ord == 20170; Hammer::Parser::Ch.new('今').parse(202.chr) == true
         # Not really unexpected though, since 20170 & 255 == 202.
         # But probably it's better to use Ch for Fixnum in 0..255 only, and only Token for strings.
         raise ArgumentError, 'expecting a one-character String' unless char.is_a?(String) && char.length == 1
-        @h_parser = Hammer::Internal.h_ch(char.ord)
-      end
+        h_parser = Hammer::Internal.h_ch(char.ord)
+
+        parser = Hammer::Parser.new
+        parser.instance_variable_set :@h_parser, h_parser
+        return parser
     end
 
-    class Sequence < Parser
-      def initialize(*parsers)
-        #args = []
-        #parsers.each { |p| args += [:pointer, p.h_parser] }
+    def self.sequence(*parsers)
         args = parsers.flat_map { |p| [:pointer, p.h_parser] }
-        @h_parser = Hammer::Internal.h_sequence(*args, :pointer, nil)
-        @sub_parsers = parsers # store them so they don't get garbage-collected (probably not needed, though)
+        h_parser = Hammer::Internal.h_sequence(*args, :pointer, nil)
+        sub_parsers = parsers # store them so they don't get garbage-collected (probably not needed, though)
         # TODO: Use (managed?) FFI struct instead of void pointers
-      end
+
+        parser = Hammer::Parser.new
+        parser.instance_variable_set :@h_parser, h_parser
+        parser.instance_variable_set :@sub_parsers, sub_parsers
+        return parser
     end
 
-    class Choice < Parser
-      def initialize(*parsers)
-        #args = []
-        #parsers.each { |p| args += [:pointer, p.h_parser] }
+    def self.choice(*parsers)
         args = parsers.flat_map { |p| [:pointer, p.h_parser] }
-        @h_parser = Hammer::Internal.h_choice(*args, :pointer, nil)
-        @sub_parsers = parsers # store them so they don't get garbage-collected (probably not needed, though)
+        h_parser = Hammer::Internal.h_choice(*args, :pointer, nil)
+        sub_parsers = parsers # store them so they don't get garbage-collected (probably not needed, though)
         # TODO: Use (managed?) FFI struct instead of void pointers
-      end
-    end
 
-    # Define parsers that take some number of other parsers
-    # TODO: Maybe use -1 for variable number, and use this for Sequence and Choice too
-    # TODO: Refactor this code as a method? And call it like: define_parser :Int64, :h_int64, 0
-    [
-      [:Int64,      :h_int64,       0],
-      [:Int32,      :h_int32,       0],
-      [:Int16,      :h_int16,       0],
-      [:Int8,       :h_int8,        0],
-      [:UInt64,     :h_uint64,      0],
-      [:UInt32,     :h_uint32,      0],
-      [:UInt16,     :h_uint16,      0],
-      [:UInt8,      :h_uint8,       0],
-      [:Whitespace, :h_whitespace,  1],
-      [:Left,       :h_left,        2],
-      [:Right,      :h_right,       2],
-      [:Middle,     :h_middle,      3],
-      [:End,        :h_end_p,       0],
-      [:Nothing,    :h_nothing_p,   0],
-      [:ButNot,     :h_butnot,      2],
-      [:Difference, :h_difference,  2],
-      [:Xor,        :h_xor,         2],
-      [:Many,       :h_many,        1],
-      [:Many1,      :h_many1,       1]
-    ].each do |class_name, h_function_name, parameter_count|
-      # Create new subclass of Hammer::Parser
-      klass = Class.new(Hammer::Parser) do
-        # Need to use define_method instead of def to be able to access h_function_name in the method's body
-        define_method :initialize do |*parsers|
-          # Checking parameter_count is not really needed, since the h_* methods will complain anyways
-          @h_parser = Hammer::Internal.send(h_function_name, *parsers.map(&:h_parser))
-          # TODO: Do we need to store sub-parsers to prevent them from getting garbage-collected?
-        end
-      end
-      # Register class with name Hammer::Parser::ClassName
-      Hammer::Parser.const_set class_name, klass
+        parser = Hammer::Parser.new
+        parser.instance_variable_set :@h_parser, h_parser
+        parser.instance_variable_set :@sub_parsers, sub_parsers
+        return parser
     end
 
-    # TODO:
-    # Hammer::Parser::Token.new('...') is a bit too long. Find a shorter way to use the parsers.
-    # Maybe:
-    #   class Hammer::Parser
-    #     def self.token(*args)
-    #       Hammer::Parser::Token.new(*args)
-    #     end
-    #   end
-    # Can create functions like that automatically. Usage:
-    #   h = Hammer::Parser
-    #   parser = h.sequence(h.token('blah'), h.token('other_token'))
-    # Looks almost like hammer in C!
-
     # Defines a parser constructor with the given name.
     # Options:
     #   hammer_function: name of the hammer function to call (default: 'h_'+name)
diff --git a/src/bindings/ruby/lib/hammer/parser_builder.rb b/src/bindings/ruby/lib/hammer/parser_builder.rb
index 2f36c844dea5ed1ebc36a89d9cee06ff56a598af..de8ce0d264a0c398396870db06d60c064177c2c4 100644
--- a/src/bindings/ruby/lib/hammer/parser_builder.rb
+++ b/src/bindings/ruby/lib/hammer/parser_builder.rb
@@ -25,7 +25,7 @@ module Hammer
 
     def build
       if @parsers.length > 1
-        Hammer::Parser::Sequence.new(*@parsers)
+        Hammer::Parser.sequence(*@parsers)
       else
         @parsers.first
       end
@@ -40,14 +40,12 @@ module Hammer
 
 
     def token(str)
-      #@h_parsers << Hammer::Internal.h_token(str, str.length)
-      @parsers << Hammer::Parser::Token.new(str)
+      @parsers << Hammer::Parser.token(str)
       return self
     end
 
     def ch(char)
-      #@h_parsers << Hammer::Internal.h_ch(char.ord)
-      @parsers << Hammer::Parser::Ch.new(char)
+      @parsers << Hammer::Parser.ch(char)
       return self
     end
 
@@ -57,17 +55,13 @@ module Hammer
       @parsers += parsers
       @parsers << Docile.dsl_eval(ParserBuilder.new, &block).build if block_given?
       return self
-      #builder = Hammer::ParserBuilder.new
-      #builder.instance_eval &block
-      #@parsers << Hammer::Parser::Sequence.new(*builder.parsers)
-      ## TODO: Save original receiver and redirect missing methods!
     end
 
     def choice(*parsers, &block)
       if block_given?
         parsers += Docile.dsl_eval(ParserBuilder.new, &block).parsers
       end
-      @parsers << Hammer::Parser::Choice.new(*parsers)
+      @parsers << Hammer::Parser.choice(*parsers)
       return self
     end
   end