Так сложилось, что раньше я имел небольшой опыт программирования на языке Java и PHP. Поэтому я с легкостью перешел на язык Ruby. Конечно мне пришлось часто обращаться к литературе, а так же замечательной утилите ri (или более удобному аналогу fxri).
Особенности языка ruby пришлись мне по душе. (такое я по-правде говоря не мог сказать после перехода с java на php)
Язык ruby богат синтаксическим сахаром. Простой цикл здесь можно записать множеством способов, и во многих случаях это улучшает читабельность программы. В прочем и сам язык позиционируется как язык программирования, вобравший в себя лучшие моменты других языков программирования.
Я хотел бы представить вам простенькую консольную утилитку, предназначенную для работы со списком задач. Она очень простая, и если данная статья кому-то придется по душе — я продолжу наращивать функционал и давать подробные разъяснения коду программы.
Чтобы запустить данную утилиту понадобится всего лишь написать в консоли:
Программа состоит из трёх файлов:
system.rb — файл содержащий реализацию работы класса System
rtodo.rb — главный исполняемый файл
list.dat — хранилище наших задач
Инструкция по работе (в примерах):
add Complete script for my web-page (добавляем задачу)
list (выводим список всех задач — у каждой задачи свой номер)
remove 1 (удаляем задачу под номером 1)


Загружаем файл, содержащий реализацию класса System
класс System отвечает за работу с задачами (добавить/удалить/показать)
создаем объект класса System
приветствуем нашего юзера
инициализируем строковую переменную, именно здесь будет хранится то, что будет вводить юзер
используя конструкцию
заносим в переменную то, что ввел наш юзер в консоле
конвертируем строку, которую ввёл юзер в массив. Каждое слово — отдельный элемент массива
если первое слово в строке, которую ввёл юзер соответствует какому-нибудь ключевому слово, тогда…
инициализируем массив, в котором будет хранится строка, которую ввел юзер. Только без первого слова, т.к. оно является ключом, и служит исключительно для работы программы
это строка заполняет массив словами
а затем объединяет слова массива в единую строку, используя пробел в качестве разделителя
на эту нижеприведённую строку стоит обратить особое внимание.
Помимо синтаксического сахара здесь встречается опасный метод eval, более подробно о нём вы можете прочесть в любой книге по php/ruby. Дело в том, что метод task_list не предусматривает аргументов, поэтому если юзер ввел команду list то аргумент функции eval будет одного вида, а если юзер ввел какую-то другую команду — то аргумент будет вполне себе стандартным для нашего класса System.
Хочу напомнить вам, этот файл непосредственно отвечает за работу с списком задач.
переменные объекта
метод-конструктор, этот метод всегда будет вызываться при создании объекта класса System
И так, для начала инициализируем хэш-массив переменной объекта @keywords
в этом массиве будут содержаться ключевые слова и названия методов
проще говоря, когда юзер введет 'add' будет вызван метод 'task_add'
создаем переменную-массив. Сюда мы будем помещать все текущие (существующую задачи)
Объясню более подробно.
В буффере хранятся все задачи юзера. Как только юзер удаляют какую либо задачу — она сначала удаляется из буфера, затем весь этот буфер записывается в файл. Иными словами — мы каждый раз заново пишем содержимое нашего файла. Для данной программы это допустимо, но в приложениях, работающих с огромными файлама — такой метод может сказаться на производительности.
файл
если файл, содержащий список задач существует
инициализируем переменную list_file, содержащую наш файл list.dat
и переписываем данные из файла в наш буфер
если этого файла не существует, то…
закрываем файл (сохраняем)
метод добавляет новое задание, в качестве аргумента — текст задачи
помещаем текст задачи в буфер
 
 
 
метод удаляет задачу, в качестве аргумента выступает номер задачи
если неверно указан аргумент
если верно
удаляем задачу из буфера
вызываем метод записывающий весь буфер в файл
вызываем метод показывающий текущий список задач (обновленный)
 
метод показывающий текущий список задач
проходимся по каждому элементу буфера
метод записывающий весь буфер в файл
открываем файл, если в качестве второго аргумента указать 'w' то каждый раз файл будет писаться заново, в отличии от альтернативного аргумента 'a'
проходимся по каждому элементу буфера
записываем текущий элемент буфера в файл
закрываем файл (сохраняем)
Хочу обратить ваше внимание на то, что это очень сырая программа. В том числе и в плане безопасности. Я не стал уделять много внимания проверке того, что вводит юзер. (а между тем, эта самая важная часть) Если данный материал придется вам по душе — то я неприменно продолжу наращивать функционал.
Скачать архив с программой [Zip, 1.2 kb]
Версия с нормальной подстветкой в моем блоге
Особенности языка ruby пришлись мне по душе. (такое я по-правде говоря не мог сказать после перехода с java на php)
Язык ruby богат синтаксическим сахаром. Простой цикл здесь можно записать множеством способов, и во многих случаях это улучшает читабельность программы. В прочем и сам язык позиционируется как язык программирования, вобравший в себя лучшие моменты других языков программирования.
Я хотел бы представить вам простенькую консольную утилитку, предназначенную для работы со списком задач. Она очень простая, и если данная статья кому-то придется по душе — я продолжу наращивать функционал и давать подробные разъяснения коду программы.
Чтобы запустить данную утилиту понадобится всего лишь написать в консоли:
$ ruby ./rtodo.rbПрограмма состоит из трёх файлов:
system.rb — файл содержащий реализацию работы класса System
rtodo.rb — главный исполняемый файл
list.dat — хранилище наших задач
Инструкция по работе (в примерах):
add Complete script for my web-page (добавляем задачу)
list (выводим список всех задач — у каждой задачи свой номер)
remove 1 (удаляем задачу под номером 1)
Для начала хочу показать исходный код без комментариев. После этого подробно распишу, что делает каждая строка.
rtodo.rb

System.rb

Начнем изучение с главного файла — rtodo.rb
Загружаем файл, содержащий реализацию класса System
load 'system.rb'класс System отвечает за работу с задачами (добавить/удалить/показать)
создаем объект класса System
system = System.newприветствуем нашего юзера
puts "> Welcome to R-todo v0.1, type 'help' to get info"инициализируем строковую переменную, именно здесь будет хранится то, что будет вводить юзер
user_input = ""используя конструкцию
while мы обрабатываем всё, что вводит юзер, до тех пор пока юзер не введет 'quit', это будет означать, что программа должна немедленно завершитьсяwhile user_input != "quit"заносим в переменную то, что ввел наш юзер в консоле
 user_input = gets.chompконвертируем строку, которую ввёл юзер в массив. Каждое слово — отдельный элемент массива
 formatted_user_input = user_input.split
далее мы будем проходиться по каждому элементу хеш-массива keywords. Вы наверное удивлены. Описание этой переменной вы найдете в файле system.rb — пока простой знайте, что этот хеш-массив содержит в себе конструкции вида 'ключевое слово' => 'вызываемая функия' system.keywords.each do |keyword,method|если первое слово в строке, которую ввёл юзер соответствует какому-нибудь ключевому слово, тогда…
 if formatted_user_input[0] == keywordинициализируем массив, в котором будет хранится строка, которую ввел юзер. Только без первого слова, т.к. оно является ключом, и служит исключительно для работы программы
 buffer = [] это строка заполняет массив словами
 1.upto(formatted_user_input.index(formatted_user_input.last)) { |index| buffer.push(formatted_user_input.at(index))}а затем объединяет слова массива в единую строку, используя пробел в качестве разделителя
 string_user_input = buffer.join(" ")на эту нижеприведённую строку стоит обратить особое внимание.
Помимо синтаксического сахара здесь встречается опасный метод eval, более подробно о нём вы можете прочесть в любой книге по php/ruby. Дело в том, что метод task_list не предусматривает аргументов, поэтому если юзер ввел команду list то аргумент функции eval будет одного вида, а если юзер ввел какую-то другую команду — то аргумент будет вполне себе стандартным для нашего класса System.
 keyword == "list" ? eval("system.#{method}") : eval("system.#{method}(string_user_input)")
 end
 end
end
puts "> R-todo was aborted by user"Переходим к файлу System.rb
Хочу напомнить вам, этот файл непосредственно отвечает за работу с списком задач.
class Systemпеременные объекта
 attr_reader :keywords, :bufferметод-конструктор, этот метод всегда будет вызываться при создании объекта класса System
 def initializeИ так, для начала инициализируем хэш-массив переменной объекта @keywords
в этом массиве будут содержаться ключевые слова и названия методов
проще говоря, когда юзер введет 'add' будет вызван метод 'task_add'
 @keywords = { 'add' => 'task_add', 'remove' => 'task_remove', 'list' => 'task_list'}создаем переменную-массив. Сюда мы будем помещать все текущие (существующую задачи)
 @buffer = []Объясню более подробно.
В буффере хранятся все задачи юзера. Как только юзер удаляют какую либо задачу — она сначала удаляется из буфера, затем весь этот буфер записывается в файл. Иными словами — мы каждый раз заново пишем содержимое нашего файла. Для данной программы это допустимо, но в приложениях, работающих с огромными файлама — такой метод может сказаться на производительности.
файл
list.dat содержит список задачесли файл, содержащий список задач существует
 if File.exist?('list.dat') инициализируем переменную list_file, содержащую наш файл list.dat
и переписываем данные из файла в наш буфер
 list_file = File.new('list.dat','r')
 list_file.each_line do |line|
 @buffer << line
 endесли этого файла не существует, то…
 else
создаем новый файл list_file = File.new("list.dat","w+") 
 puts "System files was created"
 endзакрываем файл (сохраняем)
 list_file.close
 endметод добавляет новое задание, в качестве аргумента — текст задачи
 def task_add(task)помещаем текст задачи в буфер
 @buffer << task  puts "> task added to list (#{task})"task_write_to_file вызываем метод записывающий весь буфер в файлtask_list вызываем метод показывающий текущий список задач (обновленный)endметод удаляет задачу, в качестве аргумента выступает номер задачи
 def task_remove(number)если неверно указан аргумент
 if number.to_i > (@buffer.index(@buffer.last))
 puts "> Please write a correct task index"если верно
 else
 puts "> Task #{number} removed"удаляем задачу из буфера
 @buffer.delete_at(number.to_i)вызываем метод записывающий весь буфер в файл
 task_write_to_file
 endвызываем метод показывающий текущий список задач (обновленный)
 task_list
 endметод показывающий текущий список задач
 def task_list 
 puts "********* #{@buffer.index(@buffer.last) + 1} item's *********\n"проходимся по каждому элементу буфера
 @buffer.each do |task|
 puts "\t #{@buffer.index(task)} - #{task}"
 end
 puts "\n********* #{@buffer.index(@buffer.last) + 1} item's *********"
 end
метод записывающий весь буфер в файл
 def task_write_to_fileоткрываем файл, если в качестве второго аргумента указать 'w' то каждый раз файл будет писаться заново, в отличии от альтернативного аргумента 'a'
 file = File.new('list.dat', 'w')проходимся по каждому элементу буфера
 @buffer.each do |task|записываем текущий элемент буфера в файл
 file.puts task
 endзакрываем файл (сохраняем)
 file.close
 end
end
Хочу обратить ваше внимание на то, что это очень сырая программа. В том числе и в плане безопасности. Я не стал уделять много внимания проверке того, что вводит юзер. (а между тем, эта самая важная часть) Если данный материал придется вам по душе — то я неприменно продолжу наращивать функционал.
Скачать архив с программой [Zip, 1.2 kb]
Версия с нормальной подстветкой в моем блоге
