Так сложилось, что раньше я имел небольшой опыт программирования на языке 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]
Версия с нормальной подстветкой в моем блоге