diff --git a/enumerator.c b/enumerator.c
index 11c863ad91..b3b509da5d 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -2659,6 +2659,96 @@ stop_result(VALUE self)
     return rb_attr_get(self, id_result);
 }
 
+
+static VALUE
+enumeratorgenerate_i(RB_BLOCK_CALL_FUNC_ARGLIST(yielder, enumerator))
+{
+    VALUE proc, cur;
+    cur = rb_ivar_get(enumerator, rb_intern("enumeratorgenerate_init"));
+    proc = rb_ivar_get(enumerator, rb_intern("enumeratorgenerate_proc"));
+
+    // We need to pass initial value too -- unless there were none.
+    if (cur == rb_intern("__none__")) {
+        cur = Qnil;
+    } else {
+        rb_funcallv(yielder, idLTLT, 1, &cur);
+    }
+
+    for (;;) {
+        cur = rb_proc_call(proc, rb_ary_new3(1, cur));
+        rb_funcallv(yielder, idLTLT, 1, &cur);
+    }
+
+    return Qnil;
+}
+
+/*
+ *  call-seq:
+ *     Enumerator.generate(initial) { |val| } -> enumerator
+ *     Enumerator.generate { |val| } -> enumerator
+ *
+ * Creates an infinite enumerator from any block, just called over and over.
+ * Result of the previous iteration is passed to the next one. If +initial+
+ * is provided, it is passed to the first iteration, and becomes the first
+ * element of the enumerator; if it is not provided, first iteration receives
+ * +nil+, and its result becomes first element of the iterator.
+ *
+ * One can think of this method as a Ruby's way of expressing +loop+/+while+,
+ * in the same manner as Array#each is Ruby's way of expressing +for+.
+ *
+ * Examples of usage:
+ *
+ *    # With initial value
+ *
+ *    # Simplest possible infinite sequence:
+ *    Enumerator.generate(1, &:succ) # => enumerator of 1, 2, 3, 4, ....
+ *
+ *    # Find next Tuesday
+ *    require 'date'
+ *    Enumerator.generate(Date.today, &:succ).detect(&:tuesday?)
+ *
+ *    # Some tree navigation:
+ *    Enumerator.generate(node) { |n| n.parent }.take_while { |n| n.respond_to?(:parent) }
+ *
+ *
+ *    # Without initial value
+ *
+ *    # Infinite random number sequence:
+ *    Enumerator.generate { rand(10) }
+ *
+ *    # Simple lexer:
+ *    require 'strscan'
+ *    scanner = StringScanner.new('7+38/6')
+ *    PATTERN = %r{\d+|[-+/*]}
+ *    p Enumerator.generate { scanner.scan(PATTERN) }.slice_after { scanner.eos? }.first
+ *    # => ["7", "+", "38", "/", "6"]
+ */
+static VALUE
+enumerator_generate(int argc, VALUE *argv, VALUE dummy)
+{
+    VALUE enumerator;
+    VALUE init, proc;
+
+    if (rb_scan_args(argc, argv, "01", &init) == 0) {
+        // We need a way to pass the fact that there were no start value,
+        // An `nil` is not good enough: it still can be "`nil` as a start value"
+        init = rb_intern("__none__");
+    }
+    if (!rb_block_given_p()) {
+        rb_raise(rb_eArgError, "no block given");
+    }
+
+    proc = rb_block_proc();
+
+    enumerator = rb_obj_alloc(rb_cEnumerator);
+    rb_ivar_set(enumerator, rb_intern("enumeratorgenerate_init"), init);
+    rb_ivar_set(enumerator, rb_intern("enumeratorgenerate_proc"), proc);
+
+    rb_block_call(enumerator, idInitialize, 0, 0, enumeratorgenerate_i, enumerator);
+    return enumerator;
+
+}
+
 /*
  * Document-class: Enumerator::Chain
  *
@@ -3557,6 +3647,7 @@ InitVM_Enumerator(void)
     rb_include_module(rb_cEnumerator, rb_mEnumerable);
 
     rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
+    rb_define_singleton_method(rb_cEnumerator, "generate", enumerator_generate, -1);
     rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
     rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
     rb_define_method(rb_cEnumerator, "each", enumerator_each, -1);
diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb
index 54dfebb814..600e6796bc 100644
--- a/test/ruby/test_enumerator.rb
+++ b/test/ruby/test_enumerator.rb
@@ -811,4 +811,25 @@ def test_chained_enums
       e5.inspect
     )
   end
+
+  def test_generate
+    # Without initial object
+    passed_args = []
+    enum = Enumerator.generate { |obj| passed_args << obj; (obj || 0).succ }
+    assert_instance_of(Enumerator, enum)
+    assert_equal [1, 2, 3], enum.take(3)
+    assert_equal [nil, 1, 2], passed_args
+
+    # With initial object
+    passed_args = []
+    enum = Enumerator.generate(1) { |obj| passed_args << obj; obj.succ }
+    assert_instance_of(Enumerator, enum)
+    assert_equal [1, 2, 3], enum.take(3)
+    assert_equal [1, 2], passed_args
+
+    # Without block
+    assert_raise(ArgumentError) do
+      Enumerator.generate
+    end
+  end
 end
