Repository: hylang/hy

Issue:
Remove eg/ and hy/contrib/, or make guidelines for what belongs there
eg/ and hy/contrib/ have a lot of miscellaneous stuff that isn't part of the core language. (I am, admittedly, part of the problem, having approved several pull requests that add to the latter.) So I'm inclined to think they shouldn't be in Hy's core repository. They represent a maintenance burden for the core development team, when they ought to live freely on their own elsewhere and get maintained by their individual authors, like ordinary Python packages. Python's package system is lightweight enough that it's not unreasonable to have a Python package with only 20 lines of content code.
 
If we think one of these directories or both should stay, we should have some guidelines as to what sort of code belongs and what doesn't. (CONTRIBUTING.rst is probably the right place to put such guidelines.) Like, right now, I have a lot of useful bits of code in my generic utility library [Kodhy](https://github.com/Kodiologist/Kodhy), like macros for indexing NumPy and pandas data structures, and I don't know which if any of these would be at home in contrib.

Some of this code might be of interest to Hy core development only for its tests. It can be helpful to have nontrivial programs in a programming language's test suite in addition to unit tests. If we take that philosophy towards any of the eg/ or hy/contrib/ code, it should perhaps be moved to test/.


Discussion:
Eg is useful as it shows some examples of how to use the language for various tasks. We could have a wiki, blog or something else too, but then the examples would be dead in a sense that they wouldn't be tested when hy itself changes. I would like to keep the examples there and point them out in the docs if they already aren't.

contrib on the another hand might be problematic in the future as they tend to grow (at least in quite many projects I quickly checked). I have treated it as sort of experimental side of hy, where one can introduce new features that might not yet be quite there. Eventually they could be pulled into the core if we so decide (I think this hasn't happened ever happened). But definitely, we should put up a guideline what goes here and how.
> Eg is useful as it shows some examples of how to use the language for various tasks. We could have a wiki, blog or something else too, but then the examples would be dead in a sense that they wouldn't be tested when hy itself changes.

Unless I'm missing something, they already aren't being tested. I can see that several of them haven't been updated for changes in Hy.
Good catch. Eg should go then. 
@hylang/core Any other comments before I make a PR to rip these guys out?
`eg/` is useless if not updated for changes to Hy. It might belong in its own repository for now. I don't really want to update it until Hy has stabilized more.

`hy/contrib/` has experimental candidates for the standard library. Perhaps some can be spun off to their own repositories, but other parts might belong in Hy's standard library. I think `hy/contrib/` should stay for now.

We need more experience with the contrib modules to decide what parts to keep in Hy proper, and what modifications to them are necessary for that step.
"Experimental candidates for the standard library" isn't a bad use for `contrib`, I guess. Let's run down the list of what's there now and see whether it belongs:

- `alias`: I don't see why you'd put this in the standard library. I guess it could be useful for when you're maintaining a library and you want to change the name of a function or macro but keep the old name around for a while so people's code doesn't break immediately. But that's a pretty limited purpose. I say remove it.

- `anaphoric`: This should be ready for inclusion in the standard library, although it should probably require a `require` rather than polluting the default namespace.

- `botsbuildbots`: Apparently a joke about the Portal 2 soundtrack (3f01ed5014). We ain't gonna need it. Also, it causes a test failure if you don't have an Internet connection.

- `curry`: Undocumented and of dubious value. I say remove it.

- `dispatch`: Just a utility class used by `contrib/multi`, so it should probably be moved there.

- `flow`: Not tested, and sure enough, a glance at the code suggests that `case` and `switch` will evaluate their first argument once for every clause, which is unlikely to be desirable. I say remove it, but if anybody wants to fix and test and re-add `case` (and change it to a square-bracket syntax like `cond`), be my guest.

- `loop`: A replacement is in progress over in #1166. In the meantime, I guess it can stay in /hy/contrib.

- `meth`: This seems to be specific to Flask, a web framework, so it should go.

- `multi`: Stay in /hy/contrib.

- `profile`: Stay.

- `sequences`: Stay.

- `walk`: Stay.

What do y'all think of that?

Resolving patch:
diff --git a/hy/contrib/dispatch/__init__.py b/hy/contrib/dispatch/__init__.py
deleted file mode 100644
--- a/hy/contrib/dispatch/__init__.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# -*- encoding: utf-8 -*-
-#
-# Decorator for defmulti
-#
-# Copyright (c) 2014 Morten Linderud <mcfoxax@gmail.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-from collections import defaultdict
-
-
-class MultiDispatch(object):
-    _fns = defaultdict(dict)
-
-    def __init__(self, fn):
-        self.fn = fn
-        self.__doc__ = fn.__doc__
-        if fn.__name__ not in self._fns[fn.__module__].keys():
-            self._fns[fn.__module__][fn.__name__] = {}
-        values = fn.__code__.co_varnames
-        self._fns[fn.__module__][fn.__name__][values] = fn
-
-    def is_fn(self, v, args, kwargs):
-        """Compare the given (checked fn) too the called fn"""
-        com = list(args) + list(kwargs.keys())
-        if len(com) == len(v):
-            return all([kw in com for kw in kwargs.keys()])
-        return False
-
-    def __call__(self, *args, **kwargs):
-        for i, fn in self._fns[self.fn.__module__][self.fn.__name__].items():
-            if self.is_fn(i, args, kwargs):
-                return fn(*args, **kwargs)
-        raise TypeError("No matching functions with this signature!")
diff --git a/hy/extra/__init__.py b/hy/extra/__init__.py
new file mode 100644


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -14,13 +14,10 @@
 from .native_tests.reader_macros import *  # noqa
 from .native_tests.shadow import *  # noqa
 from .native_tests.with_test import *  # noqa
-from .native_tests.contrib.anaphoric import *  # noqa
+from .native_tests.extra.anaphoric import *  # noqa
 from .native_tests.contrib.loop import *  # noqa
-from .native_tests.contrib.meth import *  # noqa
 from .native_tests.contrib.walk import *  # noqa
 from .native_tests.contrib.multi import *  # noqa
-from .native_tests.contrib.curry import *  # noqa
-from .native_tests.contrib.botsbuildbots import *  # noqa
 from .native_tests.contrib.sequences import *  # noqa
 
 if PY3:
diff --git a/tests/native_tests/contrib/alias.hy b/tests/native_tests/contrib/alias.hy
deleted file mode 100644
--- a/tests/native_tests/contrib/alias.hy
+++ /dev/null
@@ -1,8 +0,0 @@
-(require [hy.contrib.alias [defn-alias]])
-
-(defn test-defn-alias []
-  (defn-alias [tda-main tda-a1 tda-a2] [] :bazinga)
-  (assert (= (tda-main) :bazinga))
-  (assert (= (tda-a1) :bazinga))
-  (assert (= (tda-a2) :bazinga))
-  (assert (= tda-main tda-a1 tda-a2)))
diff --git a/tests/native_tests/contrib/botsbuildbots.hy b/tests/native_tests/contrib/botsbuildbots.hy
deleted file mode 100644
--- a/tests/native_tests/contrib/botsbuildbots.hy
+++ /dev/null
@@ -1,4 +0,0 @@
-(require [hy.contrib.botsbuildbots [Botsbuildbots]])
-
-(defn test-botsbuildbots []
-  (assert (> (len (first (Botsbuildbots))) 50)))
diff --git a/tests/native_tests/contrib/curry.hy b/tests/native_tests/contrib/curry.hy
deleted file mode 100644
--- a/tests/native_tests/contrib/curry.hy
+++ /dev/null
@@ -1,13 +0,0 @@
-(require [hy.contrib.curry [defnc]])
-
-
-(defnc s [x y z] ((x z) (y z)))  ; λxyz.xz(yz)
-(defnc k [x] (fn [y] x))  ; λx.λy.x
-(defnc i [x] x)  ;; λx.x 
-
-(defnc succ [n] (+ n 1))
-
-
-(defn test-curry []
-  (assert (= 16 (((((s ((((k s) k) i) i)) (i i)) ((i (i i))
-    ((((k s) i) ((s (k s)) k)) i))) succ) 0))))
diff --git a/tests/native_tests/contrib/meth.hy b/tests/native_tests/contrib/meth.hy
deleted file mode 100644
--- a/tests/native_tests/contrib/meth.hy
+++ /dev/null
@@ -1,53 +0,0 @@
-(require [hy.contrib.meth [route post-route put-route delete-route]])
-
-(defclass FakeMeth []
-  "Mocking decorator class"
-  [rules {}]
-  (defn route [self rule &kwargs options]
-    (fn [f]
-      (assoc self.rules rule (, f options))
-      f)))
-
-(defn test_route []
-  (let [app (FakeMeth)]
-    (route get-index "/" []  (str "Hy world!"))
-    (setv app-rules (getattr app "rules"))
-    (assert (in "/" app-rules))
-    (let [(, rule-fun rule-opt) (get app-rules "/")]
-      (assert (not (empty? rule-opt)))
-      (assert (in "GET" (get rule-opt "methods")))
-      (assert (= (getattr rule-fun "__name__") "get_index"))
-      (assert (= "Hy world!" (rule-fun))))))
-
-(defn test_post_route []
-  (let [app (FakeMeth)]
-    (post-route get-index "/" []  (str "Hy world!"))
-    (setv app-rules (getattr app "rules"))
-    (assert (in "/" app-rules))
-    (let [(, rule-fun rule-opt) (get app-rules "/")]
-      (assert (not (empty? rule-opt)))
-      (assert (in "POST" (get rule-opt "methods")))
-      (assert (= (getattr rule-fun "__name__") "get_index"))
-      (assert (= "Hy world!" (rule-fun))))))
-
-(defn test_put_route []
-  (let [app (FakeMeth)]
-    (put-route get-index "/" []  (str "Hy world!"))
-    (setv app-rules (getattr app "rules"))
-    (assert (in "/" app-rules))
-    (let [(, rule-fun rule-opt) (get app-rules "/")]
-      (assert (not (empty? rule-opt)))
-      (assert (in "PUT" (get rule-opt "methods")))
-      (assert (= (getattr rule-fun "__name__") "get_index"))
-      (assert (= "Hy world!" (rule-fun))))))
-
-(defn test_delete_route []
-  (let [app (FakeMeth)]
-    (delete-route get-index "/" []  (str "Hy world!"))
-    (setv app-rules (getattr app "rules"))
-    (assert (in "/" app-rules))
-    (let [(, rule-fun rule-opt) (get app-rules "/")]
-      (assert (not (empty? rule-opt)))
-      (assert (in "DELETE" (get rule-opt "methods")))
-      (assert (= (getattr rule-fun "__name__") "get_index"))
-      (assert (= "Hy world!" (rule-fun))))))
diff --git a/tests/native_tests/extra/__init__.hy b/tests/native_tests/extra/__init__.hy
new file mode 100644
diff --git a/tests/native_tests/contrib/anaphoric.hy b/tests/native_tests/extra/anaphoric.hy
similarity index 99%
rename from tests/native_tests/contrib/anaphoric.hy
rename to tests/native_tests/extra/anaphoric.hy
--- a/tests/native_tests/contrib/anaphoric.hy
+++ b/tests/native_tests/extra/anaphoric.hy
@@ -19,7 +19,7 @@
 ;; DEALINGS IN THE SOFTWARE.
 
 (import [hy.errors [HyMacroExpansionError]])
-(require [hy.contrib.anaphoric [*]])
+(require [hy.extra.anaphoric [*]])
 
 ;;;; some simple helpers