Repository: cobalt-org/liquid-rust (rust)

Issue:
Suport for-loop over `nil`
Related: #270 

Example test:
```rust
    assert_template_result!(
        "-",
        "{%for item in array%}+{%else%}-{%endfor%}",
        v!({ "array": nil }),
    );
```

- [for-loop code](https://github.com/cobalt-org/liquid-rust/blob/master/src/tags/for_block.rs)
- [Ruby implementation](https://github.com/Shopify/liquid/blob/master/lib/liquid/tags/for.rb)
- [Relevant tests](https://github.com/cobalt-org/liquid-rust/search?q=liquid+294&unscoped_q=liquid+294)
  - Once this is working, ideally the test will start failing.  We would just need to remove the `#[should_panic]` on it
  - If the test doesn't start failing, please temporarily remove `#[should_panic]`, and find or create an issue for the new failure

Pull request description:
feat(lib): Allow for-loop over `nil`
fixes #294 

I added a test in addition to removing the expected panic attribute on the conformance test, let me know if I missed anything.

- [x] Tests created for any new feature or regression tests for bugfixes.


Patch:
diff --git a/crates/lib/src/stdlib/blocks/for_block.rs b/crates/lib/src/stdlib/blocks/for_block.rs
index c4c9d74..4b9375c 100644
--- a/crates/lib/src/stdlib/blocks/for_block.rs
+++ b/crates/lib/src/stdlib/blocks/for_block.rs
@@ -132,7 +132,7 @@ fn get_array(runtime: &Runtime<'_>, array_id: &Expression) -> Result<Vec<Value>>
             })
             .collect();
         Ok(x)
-    } else if array.is_state() {
+    } else if array.is_state() || array.is_nil() {
         Ok(vec![])
     } else {
         Err(unexpected_value_error("array", Some(array.type_name())))
@@ -821,6 +821,24 @@ mod test {
         assert_eq!(output, "There are no items!");
     }
 
+    #[test]
+    fn nil_loop_invokes_else_template() {
+        let text = concat!(
+            "{% for i in nil %}",
+            "{{ i }} ",
+            "{% else %}",
+            "There are no items!",
+            "{% endfor %}"
+        );
+        let template = parser::parse(text, &options())
+            .map(runtime::Template::new)
+            .unwrap();
+
+        let mut runtime = Runtime::new();
+        let output = template.render(&mut runtime).unwrap();
+        assert_eq!(output, "There are no items!");
+    }
+
     #[test]
     fn limit_greater_than_iterator_length() {
         let text = concat!("{% for i in (1..5) limit:10 %}", "{{ i }} ", "{% endfor %}");


Test patch:
diff --git a/tests/conformance_ruby/tags/for_tag_test.rs b/tests/conformance_ruby/tags/for_tag_test.rs
index 205044b..26d8b08 100644
--- a/tests/conformance_ruby/tags/for_tag_test.rs
+++ b/tests/conformance_ruby/tags/for_tag_test.rs
@@ -171,7 +171,6 @@ fn test_for_and_if() {
 }
 
 #[test]
-#[should_panic] // liquid-rust#294
 fn test_for_else() {
     assert_template_result!(
         "+++",