diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..602a578 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.json +*.rss +*.atom +*.txt diff --git a/lesson04/homework/Converter/README.md b/lesson04/homework/Converter/README.md new file mode 100644 index 0000000..ebb39fa --- /dev/null +++ b/lesson04/homework/Converter/README.md @@ -0,0 +1,6 @@ +В данном репозитории находится конвертер из RSS формата в форматы ATOM, JSON и наоборот. + +Для использования программы используются следующие обязательные аттрибуты: +-i --input=FILE //Входной файл +-o --output=FORMAT //Выходной формат + diff --git a/lesson04/homework/Converter/bin/optionParser.rb b/lesson04/homework/Converter/bin/optionParser.rb new file mode 100644 index 0000000..0b59706 --- /dev/null +++ b/lesson04/homework/Converter/bin/optionParser.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'optparse' + +class Parser +@options = {} + def self.parse() + OptionParser.new do |parser| + parser.on('-i', '--input=FILE', + 'File to convert') + + parser.on('-o', '--output=FORMAT', + 'Choose one of the formats: json, atom, rss') + + parser.on('-h', '--help', 'Prints this help') do + puts parser + exit + end + end.parse!(into: @options) + @options +end +end diff --git a/lesson04/homework/Converter/convert.rb b/lesson04/homework/Converter/convert.rb new file mode 100644 index 0000000..d923e62 --- /dev/null +++ b/lesson04/homework/Converter/convert.rb @@ -0,0 +1,13 @@ +require 'require_all' +require '~/converter/main.rb' +require 'nokogiri' +require 'feedjira' +require 'json' + +require_all 'lib' +require_all 'bin' + +options = Parser.parse +p options +main = Main.new(options) +main.run diff --git a/lesson04/homework/Converter/lib/check/check.rb b/lesson04/homework/Converter/lib/check/check.rb new file mode 100644 index 0000000..37d6d1c --- /dev/null +++ b/lesson04/homework/Converter/lib/check/check.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Check + def self.valid_json?(json) + JSON.parse(json) + true + rescue JSON::ParserError => e + false + end + + def self.check(data) + str = data.to_s + if str.include? ' doc.css('channel image url').text.strip, + 'title' => doc.css('channel image title').text.strip, + 'link' => doc.css('channel image link').text.strip } + + parsedString.push( + language: feed_language, + title: feed_title, + description: feed_description, + link: feed_link, + image: feed_image_content + ) + end + + def self.parseItems(doc) + items = [] + + item_tags = doc.xpath('//item/*').map(&:name).each.uniq + p item_tags + doc.css('item').each do |item| + parsed_strings = {} + attr_names = [] + item_tags.each do |tag| + attr_hash = {} + if !doc.xpath("//item/#{tag}[@*]").empty? # if tag has attribute parse them + attr_names = doc.xpath("//item/#{tag}/@*").map(&:name).each.uniq + attr_names.each do |att| + attr_hash[att] = item.css(tag)[0][att] + end + parsed_strings[tag] = attr_hash + else + item_result = item.css(tag.to_s).text.strip + parsed_strings[tag] = item_result + end + end + items.push << parsed_strings + end + items + end + + def self.parse(doc) + doc = Nokogiri::XML(doc) + result = { feed: parseFeed(doc), + items: parseItems(doc) } + end +end diff --git a/lesson04/homework/Converter/lib/readers/file_reader.rb b/lesson04/homework/Converter/lib/readers/file_reader.rb new file mode 100644 index 0000000..6d95d55 --- /dev/null +++ b/lesson04/homework/Converter/lib/readers/file_reader.rb @@ -0,0 +1,6 @@ +module File_reader + def self.read(path) + file = File.open(path) + data = file.read + end +end diff --git a/lesson04/homework/Converter/lib/readers/link_reader.rb b/lesson04/homework/Converter/lib/readers/link_reader.rb new file mode 100644 index 0000000..1b053a5 --- /dev/null +++ b/lesson04/homework/Converter/lib/readers/link_reader.rb @@ -0,0 +1,7 @@ +require 'open-uri' + +module Link_reader + def self.read(url) + data = open(url).read + end +end diff --git a/lesson04/homework/Converter/main.rb b/lesson04/homework/Converter/main.rb new file mode 100644 index 0000000..87b7169 --- /dev/null +++ b/lesson04/homework/Converter/main.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +class Main + def initialize(options) + @input = options[:input] + @output_format = options[:output] + @sort = options[:sort] + end + + def run + data = if @input.match('^https|http') + Link_reader.read(@input) + else + File_reader.read(@input) + end + + parsed_data = if Check.check(data) == 'atom' + ParseAtom.parse(data) + elsif Check.check(data) == 'rss' + ParseRss.parse(data) + elsif Check.check(data) == 'json' + ParseJson.parse(data) + else + p 'ERROR' + end + + if @output.to_s.downcase == 'atom' + ConvertToAtom.convert(parsed_data) + elsif @output.to_s.downcase == 'rss' + ConvertToRss.convert(parsed_data) + else + ConvertToJson.convert(parsed_data) + end + end +end diff --git a/lesson04/homework/converter/.gitignore b/lesson04/homework/converter/.gitignore new file mode 100644 index 0000000..9814688 --- /dev/null +++ b/lesson04/homework/converter/.gitignore @@ -0,0 +1,6 @@ +*.json +*.txt +*.swp +*.yml +*.atom +*.rss diff --git a/lesson04/homework/converter/README.md b/lesson04/homework/converter/README.md new file mode 100644 index 0000000..3bc8018 --- /dev/null +++ b/lesson04/homework/converter/README.md @@ -0,0 +1,10 @@ +В данном репозитории находится конвертер из RSS формата в форматы ATOM, JSON и наоборот. + +Для использования программы используются следующие обязательные аттрибуты: +-i --input=FILE //Входной файл +-o --output=FORMAT //Выходной формат + +Необязательный аттрибут для названия выходного файла: +-n --name=FILE //Имя выходного файла + +При отсутствии данного аттрибута, данные запишутся в файл output.txt diff --git a/lesson04/homework/converter/bin/option_parser.rb b/lesson04/homework/converter/bin/option_parser.rb new file mode 100644 index 0000000..95e2446 --- /dev/null +++ b/lesson04/homework/converter/bin/option_parser.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'optparse' + +# parse options +class OptionParser + @options = {} + def self.parse + OptionParser.new do |parser| + parser.on('-i', '--input=FILE', + 'File to convert') + + parser.on('-o', '--output=FORMAT', + 'Choose one of the formats: json, atom, rss') + parser.on('-n', '--name=FILE', + 'Type converted file name') + parser.on('-h', '--help', 'Prints this help') do + exit + end + end.parse!(into: @options) + @options + end +end diff --git a/lesson04/homework/converter/convert.rb b/lesson04/homework/converter/convert.rb new file mode 100644 index 0000000..42a92bd --- /dev/null +++ b/lesson04/homework/converter/convert.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'require_all' +require '~/converter/main.rb' + +require_all 'lib' +require_all 'bin' + +options = OptionParser.parse +main = Main.new(options) +main.run diff --git a/lesson04/homework/converter/lib/check/check_format.rb b/lesson04/homework/converter/lib/check/check_format.rb new file mode 100644 index 0000000..0f6e279 --- /dev/null +++ b/lesson04/homework/converter/lib/check/check_format.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# Check if input data matches one of the three formats: Atom, RSS, JSON +module Check + def self.valid_json?(json) + JSON.parse(json) + true + rescue JSON::ParserError => e + false + end + + def self.check(data) + str = data.to_s + if str.include? ' '2.0', 'xmlns:atom' => 'http://www.w3.org/2005/Atom') do + data.values[0].each do |v| + xml.entry do + xml.title v[:title] + xml.summary v[:description] + xml.published v[:pubdate] + end + end + end + end + builder.to_xml + end +end diff --git a/lesson04/homework/converter/lib/converters/modules/convert_to_json.rb b/lesson04/homework/converter/lib/converters/modules/convert_to_json.rb new file mode 100644 index 0000000..215c18e --- /dev/null +++ b/lesson04/homework/converter/lib/converters/modules/convert_to_json.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'json' + +# Class which converts hash data to Json format +module ConvertToJson + def self.convert(data) + JSON.pretty_generate(data) + end +end diff --git a/lesson04/homework/converter/lib/converters/modules/convert_to_rss.rb b/lesson04/homework/converter/lib/converters/modules/convert_to_rss.rb new file mode 100644 index 0000000..780e919 --- /dev/null +++ b/lesson04/homework/converter/lib/converters/modules/convert_to_rss.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'nokogiri' + +# Class which converts hash data to RSS format + +module ConvertToRss + def self.convert(data) + builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| + xml.rss('version' => '2.0', 'xmlns:atom' => 'http://www.w3.org/2005/Atom') do + data.values[0].each do |v| + xml.item do + xml.title v[:title] + xml.description v[:description] + xml.pubDate v[:pubdate] + end + end + end + end + builder.to_xml + end +end diff --git a/lesson04/homework/converter/lib/parsers/base_parser.rb b/lesson04/homework/converter/lib/parsers/base_parser.rb new file mode 100644 index 0000000..d9c8801 --- /dev/null +++ b/lesson04/homework/converter/lib/parsers/base_parser.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +Dir['lib/parsers/modules/*.rb'].each do |file| + require File.expand_path(file) +end + +# parse data +module BaseParser + def self.parse(data) + parsers = ClassList.names('lib/parsers/modules/*rb') + parsers.each do |parser| + class_name = Module.const_get(parser) + return class_name.parse(data) if class_name.can_parse?(data) + end + end +end diff --git a/lesson04/homework/converter/lib/parsers/modules/atom_parser.rb b/lesson04/homework/converter/lib/parsers/modules/atom_parser.rb new file mode 100644 index 0000000..b947f93 --- /dev/null +++ b/lesson04/homework/converter/lib/parsers/modules/atom_parser.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'nokogiri' + +# This module parse Atom feed and entries +module AtomParser + def self.can_parse?(doc) + doc = Nokogiri::XML(doc) + doc.remove_namespaces! + return true if doc.xpath('boolean(//entry)') + + false + end + + def self.parse_feed(doc) + parsed_string = [] + feed_title = doc.at_css('feed title').text.strip + + parsed_string.push( + title: feed_title + ) + end + + def self.parse_entry(doc) + items = [] + + doc.css('entry').each do |item| + entry_title = item.css('title').text.strip + entry_summary = item.css('summary').text.strip + entry_pubdate = item.css('published').text.strip + items.push( + title: entry_title, + description: entry_summary, + pubdate: entry_pubdate + ) + end + items + end + + def self.parse(doc) + doc = Nokogiri::XML(doc) + doc.remove_namespaces! + + result = { + # feed: parse_feed(doc), + entry: parse_entry(doc) + } + end +end diff --git a/lesson04/homework/converter/lib/parsers/modules/json_parser.rb b/lesson04/homework/converter/lib/parsers/modules/json_parser.rb new file mode 100644 index 0000000..d1db49c --- /dev/null +++ b/lesson04/homework/converter/lib/parsers/modules/json_parser.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'json' + +# Methods for checking if we can parse and method for parse itself +module JsonParser + def self.can_parse?(data) + JSON.parse(data) + true + rescue JSON::ParserError => e + false + end + + def self.parse(data) + data = JSON.parse(data) + end +end diff --git a/lesson04/homework/converter/lib/parsers/modules/rss_parser.rb b/lesson04/homework/converter/lib/parsers/modules/rss_parser.rb new file mode 100755 index 0000000..eab6e52 --- /dev/null +++ b/lesson04/homework/converter/lib/parsers/modules/rss_parser.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'nokogiri' + +# Parse rss format +module RssParser + def self.can_parse?(doc) + doc = Nokogiri::XML(doc) + doc.remove_namespaces! + return true if doc.xpath('boolean(//item)') + + false + end + + def self.parse_feed(doc) + parsed_string = [] + feed_title = doc.at_css('channel title').text + + parsed_string.push( + title: feed_title + ) + end + + def self.parse_items(doc) + items = [] + + doc.css('item').each do |item| + item_title = item.css('title').text.strip + item_description = item.css('description').text.strip + item_pubdate = item.css('pubDate').text.strip + items.push( + title: item_title, + description: item_description, + pubDate: item_pubdate + ) + end + items + end + + def self.parse(doc) + doc = Nokogiri::XML(doc) + result = { # feed: parse_feed(doc), + items: parse_items(doc) + } + end +end diff --git a/lesson04/homework/converter/lib/readers/file_reader.rb b/lesson04/homework/converter/lib/readers/file_reader.rb new file mode 100644 index 0000000..70fb076 --- /dev/null +++ b/lesson04/homework/converter/lib/readers/file_reader.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module File_reader + def self.read(path) + file = File.open(path) + data = file.read + end +end diff --git a/lesson04/homework/converter/lib/readers/link_reader.rb b/lesson04/homework/converter/lib/readers/link_reader.rb new file mode 100644 index 0000000..3c2e8a0 --- /dev/null +++ b/lesson04/homework/converter/lib/readers/link_reader.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'open-uri' + +module Link_reader + def self.read(url) + open(url).read + end +end diff --git a/lesson04/homework/converter/lib/sorters/date_sort.rb b/lesson04/homework/converter/lib/sorters/date_sort.rb new file mode 100644 index 0000000..9fc1394 --- /dev/null +++ b/lesson04/homework/converter/lib/sorters/date_sort.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# sort hash +# module DateSort +# def sort(data) + +# end +# end diff --git a/lesson04/homework/converter/lib/tools/class_list.rb b/lesson04/homework/converter/lib/tools/class_list.rb new file mode 100644 index 0000000..711f191 --- /dev/null +++ b/lesson04/homework/converter/lib/tools/class_list.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module ClassList + def self.names(path) + parsers = Dir[path].map do |file| + File.basename(file, '*.rb').split('_').map(&:capitalize).join.sub!('.rb', '') + end + parsers + end +end diff --git a/lesson04/homework/converter/lib/writer/file_writer.rb b/lesson04/homework/converter/lib/writer/file_writer.rb new file mode 100644 index 0000000..527988d --- /dev/null +++ b/lesson04/homework/converter/lib/writer/file_writer.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# Write data to file +module FileWriter + def self.write(data, filename) + filename = 'output.txt' if filename.nil? + File.write(filename, data) + end +end diff --git a/lesson04/homework/converter/main.rb b/lesson04/homework/converter/main.rb new file mode 100644 index 0000000..6e500b6 --- /dev/null +++ b/lesson04/homework/converter/main.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'nokogiri' + +# Main class +class Main + def initialize(options) + @input = options[:input] + @output = options[:output] + @sort = options[:sort] + @name = options[:name] + end + + def run + data = if @input.match('^https|http') + Link_reader.read(@input) + else + File_reader.read(@input) + end + + parsed_data = BaseParser.parse(data) + converted_data = BaseConverter.convert(parsed_data, @output) + FileWriter.write(converted_data, @name) + end +end