Xmenu — маленький «фреймворк» для построения консольных меню

Доброго времени суток, дорогие хабралюди! Так уж случилось, что по долгу службы выпало мне писать консольное приложение (меню) для решения насущных проблем связанных с миграциями баз данных (да и не только миграциями, но и с другим, разного вида, обслуживанием). Сразу оговорюсь, что о миграцих речь под катом не пойдет! Разработка ведется на языке Python, поэтому далее следует непереводимая игра слов с использованием национальных диалектов.
Текущая поделка сослуживца представляла из себя пластилиновый шарик плотно слепленных и переплетенных друг с другом частей. Поэтому, что-либо изменить, дополнить или на худой конец понять, в том коде я не смог, поэтому решил переписать данную балалайку, предварительно разделив архитектурные компоненты. Пошел в Сеть на поиски python-фреймворка для построения консольных менюшек. Поиски не увенчались успехом — не нашлось просто в Сети фреймворков для построение хотя бы мало-мальски пригодного к использованию меню. Но вот нашел двух " почти кандидатов": cliff не совсем соответствует моим запросам т.к. это не консольное меню, собственно, а просто интерактивный сеанс (командная строка) в которой возможно руками вводить команды и наслаждаться автодополнением. Не то. console совсем не соответствует желаниям т.к. это
тот же сыр, но под другим соусом
Тем более, более чем сырой. Простите за тафталогию.
Начать я, собственно, решил с написания пары классов для отрисовки консольного меню (основу отрисовки услужливо предоставил мне модуль cmd2, который, как следствие требуется для работы с моим маленьким xmenu). Собственно в реализации никаких хитростей нет. Тройка классов, корутина для хранения истории — вот и весь сказ. Получился вот такой мини-фреймворк. Прошу не начинать сразу плеваться, т.к. призываю Вас знать, что это pre-alpha версия. А забрать и посмотреть xmenu можно на гитхабе. А тем, кому не хочется разбираться в отсутствующей докуметации (пока, отсутствующей), опубликую пример клиентского кода вот здесь:
# -*- coding: utf-8 -*-
import sys
from pymenu import Item, Menu, App


class Twitter(Item):
    ''' This is twitter'''

    def __call__(self):
        sys.stdout.write('{0}\n'.format(self.name))


class Multiplier(Item):
    ''' Printing 1. Forever 1.'''

    def __call__(self):
        sys.stdout.write('Lorem ipsum Labor Excepteur ea ut.')


def func():
    ''' I am a function. Tasty and fragrand.'''

    print 'This is it.'


class MyApp(App):
    ''' This is my App'''

    def __init__(self):

        menu = Menu(name='Main menu')
        menu.add(Twitter(name='Project run'), color='red')
        menu.add(Twitter(name='Other'))
        math = Menu(name='Math')
        math.add(Multiplier(name='Multi'), color='underline')
        inc_menu = Menu(name='Database')
        inc_menu.add(math)
        inc_menu.add(Twitter(name='Create'))
        inc_menu.add(Twitter(name='Drop'))
        menu.add(inc_menu)
        functinons = Menu(name='Functinons', doc='Useful functions!')
        functinons.add(func, name='f')
        menu.add(functinons, color='underline')
        super(MyApp, self).__init__(menu=menu, stdout=sys.stdout)


def main():
    MyApp().run()


if __name__ == '__main__':
    main()

Получится вот так:

Это абсолютно хаотичное меню — по наполнению не судите.
Итак, xmenu обеспечивает:
  • Меню бесконечной вложенности (меню вкладываются в меню)
  • Раскрашивание элементов меню
  • Возможность ходить по истории назад (в будущем быть может сделаю хождение и вперед)
  • На пункты меню можно навешивать любые callable-объекты
  • Xmenu автоматически собирает доки со всех объектов и аггрегирует их в одном меню — help.

Я пока не такой активный деятель движения открытого программного обеспечения, но обещаю двигаться в этом направлении, буду развивать и дополнять сей инструмент. Спасибо всем, кто дочитал до этого предложения, и особенное спасибо тем, кто затестил, высказал свои пожелания и осветил мои огрехи. И видит Хабр, быть может я не зря старался, ведь это моя первая статья и я только учусь быть хабрачеловеком.
UPD: версия либы обновилась — спишите видеть на гитхабе
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 11

    0
    Вам не кажется, что было бы намного понятнее, если бы это выглядело так:

    menu = MenuItem('Main menu', sub_items = [
    MenuItem('Functions', style=...),
    TwitterMenuItem(style=...)
    ]

    render(menu)

    Потому что сейчас ваш инит-метод — макароны.
    P.S. Простите, не работают теги =(
      0
      Да, есть такое. Но это просто прототип. Подумав, я реорганизую работу с объектами, и скорее всего сделаю просто регистрации меню в главном приложении и последующем запуске последнего. Думаю, так будет лучше. Спасибо за вкусный комментарий. И да — Вы правы — макароны в коде это плохо:)
      0
      Посмотрите на то, как делали в Turbo Vision, если уж хочется объектной ориентированности. Ну или просто вложенные словари-списки типа вот этого. Там на тикле, правда, но на питоне даже проще будет, т.к. у вас типизация более явно выражена в языке.
        0
        Спасибо за предложение. Я обязательно ознакомлюсь! Это предложение рождено неконструктивностью кода? Или это просто как вариант того, как могло бы быть реализовано подобное приложение?
          0
          По-моему, у Вас слишком много кода, причём слабо структурированного, а потому не очень читаемого. В Turbo Vision сделали так, что код получается как раз соответствующим структуре создаваемых объектов (приблизительно). Но лучше, на мой взгляд, описывать меню структурой данных, по которой одним вызовом можно это меню сконструировать. Таки данные гораздо читаемее, ну да и динамичности прибавляют коду — их всегда легче заменить, чем собственно код.
        –2
        меню в консоли — что за ересь.
          –1
          Меню в консоли очень удобно в том случае, когда нужно постоянно выбирать что-то из имеющихся вариантов (списки файлов кастомных каких-то), либо когда нужно использовать данную тулзу человеку, не сведующему в деталях работы с каким либо механизмом. Живой пример — миграции баз данных. Ради чего этот фреймик и родился, Уважаемый. А порочить и поносить неконструктивно каждый может. Вам сюда — поболтать с братюней. Неудивительно, что у вас такой рэйтинг… и карма.
            0
            единcтвенный расово верный сбособ интерактивного взаимодейсвия в CLI это имеено автодополнение. отсюда и отсутствие «фреймворков для построения меню» (слово то какое! просто «библиотека» ща не в моде)
              0
              Всё это правильно и хорошо и согласен я. Но вот понадобилось меню и есть оно независимо от расс и вер. А фреймворком это не называется at all, поэтому это слово фреймворк и в кавычках.
          0
          Могу предложить вам посмотреть на интерфейс командной строки утилиты zenity — для простых случаев меню/диалогов в 1-2-3 уровня вложенности — самое оно! И можно прикрутить в текущую реализацию, например в качестве CLI при запуске библиотеки в роли скрипта.
            0
            Надо будет позаимствовать там что-нибудь;)

          Only users with full accounts can post comments. Log in, please.