diff --git a/src/bindings/ruby/lib/hammer.rb b/src/bindings/ruby/lib/hammer.rb
index cfb62dcb768d7614c933d6fceb204e6cff82f6d3..63ac2c79d305688e4080bc07bf354285fcc964a9 100644
--- a/src/bindings/ruby/lib/hammer.rb
+++ b/src/bindings/ruby/lib/hammer.rb
@@ -20,3 +20,25 @@ x.bind(Hammer::Parser.token('abd'))
 $r = parser.parse 'abcabd'
 
 p $r[:ast][:data][:seq].elements.map {|e| e[:data][:bytes].token }
+
+
+h = Hammer::Parser
+parser =
+  h.many(
+    h.action(h.uint8) { |r|
+      p "TT=#{r[:ast][:token_type]}, value=#{r[:ast][:data][:uint]}"
+      r[:ast][:data][:uint] *= 2
+      r[:ast] if r[:ast][:data][:uint] % 3 == 0
+    })
+
+#parser = Hammer::Parser.build {
+#  many {
+#    uint8
+#    action { |r|
+#      p r
+#      r[:ast]
+#    }
+#  }
+#}
+$r = parser.parse 'abcdefgh'
+p $r[:ast][:data][:seq].elements.map {|e| e[:data][:uint]}
diff --git a/src/bindings/ruby/lib/hammer/internal.rb b/src/bindings/ruby/lib/hammer/internal.rb
index 12d797f5a8007a1cfd43e3ca1b7848c7bc5a6baa..bceff326c54a8699017a3a9200107336e6627b8a 100644
--- a/src/bindings/ruby/lib/hammer/internal.rb
+++ b/src/bindings/ruby/lib/hammer/internal.rb
@@ -119,7 +119,8 @@ module Hammer
     attach_function :h_indirect, [], :h_parser
     attach_function :h_bind_indirect, [:h_parser, :h_parser], :void
 
-    #attach_function :h_action, [:h_parser, ...], :h_parser
+    callback :HAction, [HParseResult.by_ref], HParsedToken.by_ref
+    attach_function :h_action, [:h_parser, :HAction], :h_parser
     #attach_function :h_attr_bool, [:h_parser, ...], :h_parser
 
     # free the parse result
diff --git a/src/bindings/ruby/lib/hammer/parser.rb b/src/bindings/ruby/lib/hammer/parser.rb
index c0c1cfc8416d159d28c0689c0cbbd1c1de61d5b7..f9ff4c703106757242b7ad493ce01e352ee0b862 100644
--- a/src/bindings/ruby/lib/hammer/parser.rb
+++ b/src/bindings/ruby/lib/hammer/parser.rb
@@ -45,6 +45,15 @@ module Hammer
       @dont_gc << other_parser
     end
 
+    # Can pass the action either as a Proc in second parameter, or as block.
+    def self.action(parser, action=nil, &block)
+      action = block if action.nil?
+      raise ArgumentError, 'no action' if action.nil?
+
+      h_parser = Hammer::Internal.h_action(parser.h_parser, action)
+      return Hammer::Parser.new(:action, h_parser, [parser, action])
+    end
+
     def self.token(string)
       # Need to copy string to a memory buffer (not just string.dup)
       # * Original string might be modified, this must not affect existing tokens
diff --git a/src/bindings/ruby/lib/hammer/parser_builder.rb b/src/bindings/ruby/lib/hammer/parser_builder.rb
index d610db9cec397c475fbcd939c90f61de74a2ab94..6756314aacaa7d72b35056c5f8ec2a820ccc12c8 100644
--- a/src/bindings/ruby/lib/hammer/parser_builder.rb
+++ b/src/bindings/ruby/lib/hammer/parser_builder.rb
@@ -52,9 +52,18 @@ module Hammer
       return self
     end
 
+    # modifies previous parser
+    def action(&block)
+      parser = @parsers.last
+      raise RuntimeError, 'need a parser before action' if parser.nil?
+      @parsers << Hammer::Parser.action(parser, &block)
+      return self
+    end
+
     # Defines a parser constructor with the given name.
     def self.define_parser(name, options = {})
       define_method name do |*args|
+        # TODO: This is wrong!! Needs to accept a block for nested parsers!
         @parsers << Hammer::Parser.send(name, *args)
         return self
       end