From 473407048c27403cc3c678418f9d503a29071e52 Mon Sep 17 00:00:00 2001 From: Rikuoh Date: Sun, 28 Jul 2024 20:53:15 +0900 Subject: [PATCH] =?UTF-8?q?wc=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89=E6=94=B9?= =?UTF-8?q?=E8=89=AF&&=E3=83=A1=E3=83=A2=E3=82=A2=E3=83=97=E3=83=AA?= =?UTF-8?q?=E8=A9=A6=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memoapp/Gemfile | 4 + memoapp/Gemfile.lock | 38 ++++++++++ memoapp/README.md | 2 + memoapp/app.rb | 62 ++++++++++++++++ memoapp/public/memos.json | 10 +++ memoapp/public/styles.css | 149 ++++++++++++++++++++++++++++++++++++++ memoapp/views/edit.erb | 8 ++ memoapp/views/index.erb | 5 ++ memoapp/views/layout.erb | 22 ++++++ memoapp/views/new.erb | 7 ++ memoapp/views/show.erb | 14 ++++ wc.rb | 26 ++++--- 12 files changed, 337 insertions(+), 10 deletions(-) create mode 100644 memoapp/Gemfile create mode 100644 memoapp/Gemfile.lock create mode 100644 memoapp/README.md create mode 100644 memoapp/app.rb create mode 100644 memoapp/public/memos.json create mode 100644 memoapp/public/styles.css create mode 100644 memoapp/views/edit.erb create mode 100644 memoapp/views/index.erb create mode 100644 memoapp/views/layout.erb create mode 100644 memoapp/views/new.erb create mode 100644 memoapp/views/show.erb diff --git a/memoapp/Gemfile b/memoapp/Gemfile new file mode 100644 index 0000000..de9ea2b --- /dev/null +++ b/memoapp/Gemfile @@ -0,0 +1,4 @@ +source "https://rubygems.org" + +gem "sinatra" +gem "sinatra-contrib" diff --git a/memoapp/Gemfile.lock b/memoapp/Gemfile.lock new file mode 100644 index 0000000..8c0dd3f --- /dev/null +++ b/memoapp/Gemfile.lock @@ -0,0 +1,38 @@ +GEM + remote: https://rubygems.org/ + specs: + base64 (0.2.0) + multi_json (1.15.0) + mustermann (3.0.0) + ruby2_keywords (~> 0.0.1) + rack (3.1.7) + rack-protection (4.0.0) + base64 (>= 0.1.0) + rack (>= 3.0.0, < 4) + rack-session (2.0.0) + rack (>= 3.0.0) + ruby2_keywords (0.0.5) + sinatra (4.0.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.0.0) + rack-session (>= 2.0.0, < 3) + tilt (~> 2.0) + sinatra-contrib (4.0.0) + multi_json (>= 0.0.2) + mustermann (~> 3.0) + rack-protection (= 4.0.0) + sinatra (= 4.0.0) + tilt (~> 2.0) + tilt (2.4.0) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + sinatra + sinatra-contrib + +BUNDLED WITH + 2.5.11 diff --git a/memoapp/README.md b/memoapp/README.md new file mode 100644 index 0000000..e4e9544 --- /dev/null +++ b/memoapp/README.md @@ -0,0 +1,2 @@ +# memoapp +Sinatraでシンプルなメモアプリを作る diff --git a/memoapp/app.rb b/memoapp/app.rb new file mode 100644 index 0000000..8d7db94 --- /dev/null +++ b/memoapp/app.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'sinatra' +require 'sinatra/reloader' if development? +require 'json' + +FILE_PATH = 'public/memos.json' + +def load_memos + File.exist?(FILE_PATH) ? JSON.parse(File.read(FILE_PATH)) : {} +end + +def save_memos(memos) + File.open(FILE_PATH, 'w') do |file| + file.write(JSON.pretty_generate(memos)) + end +end + +get '/' do + redirect '/memos' +end + +get '/memos' do + @memos = load_memos + erb :index +end + +get '/memos/new' do + erb :new +end + +post '/memos' do + memos = load_memos + id = (memos.keys.map(&:to_i).max || 0) + 1 + memos[id.to_s] = { 'title' => params[:title], 'content' => params[:content] } + save_memos(memos) + redirect '/memos' +end + +get '/memos/:id' do + @memo = load_memos[params[:id]] + erb :show +end + +get '/memos/:id/edit' do + @memo = load_memos[params[:id]] + erb :edit +end + +patch '/memos/:id' do + memos = load_memos + memos[params[:id]] = { 'title' => params[:title], 'content' => params[:content] } + save_memos(memos) + redirect "/memos/#{params[:id]}" +end + +delete '/memos/:id' do + memos = load_memos + memos.delete(params[:id]) + save_memos(memos) + redirect '/memos' +end diff --git a/memoapp/public/memos.json b/memoapp/public/memos.json new file mode 100644 index 0000000..e33e587 --- /dev/null +++ b/memoapp/public/memos.json @@ -0,0 +1,10 @@ +{ + "1": { + "title": "あ", + "content": "い" + }, + "2": { + "title": "い", + "content": "え" + } +} \ No newline at end of file diff --git a/memoapp/public/styles.css b/memoapp/public/styles.css new file mode 100644 index 0000000..d5f0baf --- /dev/null +++ b/memoapp/public/styles.css @@ -0,0 +1,149 @@ +body { + font-family: Arial, sans-serif; + background-color: #f0f0f0; + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} + +.container { + background-color: #fff; + padding: 20px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + border-radius: 8px; + width: 300px; +} + +header { + text-align: center; + margin-bottom: 20px; +} + +header h1 { + font-size: 24px; + margin: 0; +} + +nav { + margin-bottom: 20px; + text-align: center; +} + +nav a { + margin: 0 10px; + text-decoration: none; + color: #007bff; +} + +nav a:hover { + text-decoration: underline; +} + +form { + display: flex; + flex-direction: column; +} + +form label { + margin-bottom: 5px; +} + +form input[type="text"], +form textarea { + margin-bottom: 10px; + padding: 10px; + border: 1px solid #ddd; + border-radius: 4px; +} + +form button { + padding: 10px; + color: #fff; + border: none; + border-radius: 4px; + cursor: pointer; +} + +form button.save { + background-color: #007bff; +} + +form button.save:hover { + background-color: #0056b3; +} + +form button.delete { + background-color: #dc3545; +} + +form button.delete:hover { + background-color: #c82333; +} + +form button.edit { + background-color: #28a745; +} + +form button.edit:hover { + background-color: #218838; +} + +form button.back { + background-color: #6c757d; +} + +form button.back:hover { + background-color: #5a6268; +} + +.memo-list { + list-style: none; + padding: 0; +} + +.memo-list li { + margin-bottom: 10px; +} + +.memo-list a { + text-decoration: none; + color: #007bff; +} + +.memo-list a:hover { + text-decoration: underline; +} + +.memo-actions { + display: flex; + justify-content: space-between; + margin-bottom: 10px; /* 追加: 「戻る」ボタンの上に余白を追加 */ +} + +.memo-actions form { + display: inline; +} + +.memo-actions button { + padding: 10px; + color: #fff; + border: none; + border-radius: 4px; + cursor: pointer; +} + +.memo-actions .edit { + background-color: #28a745; /* 緑色に統一 */ +} + +.memo-actions .edit:hover { + background-color: #218838; +} + +.memo-actions .back { + background-color: #6c757d; +} + diff --git a/memoapp/views/edit.erb b/memoapp/views/edit.erb new file mode 100644 index 0000000..54c58b0 --- /dev/null +++ b/memoapp/views/edit.erb @@ -0,0 +1,8 @@ +
+ + +"> + + + +
diff --git a/memoapp/views/index.erb b/memoapp/views/index.erb new file mode 100644 index 0000000..47b644e --- /dev/null +++ b/memoapp/views/index.erb @@ -0,0 +1,5 @@ + diff --git a/memoapp/views/layout.erb b/memoapp/views/layout.erb new file mode 100644 index 0000000..f99734c --- /dev/null +++ b/memoapp/views/layout.erb @@ -0,0 +1,22 @@ + + + + + メモアプリ + + + +
+
+

メモアプリ

+
+ +
+ <%= yield %> +
+
+ + diff --git a/memoapp/views/new.erb b/memoapp/views/new.erb new file mode 100644 index 0000000..125b083 --- /dev/null +++ b/memoapp/views/new.erb @@ -0,0 +1,7 @@ +
+ + + + + +
diff --git a/memoapp/views/show.erb b/memoapp/views/show.erb new file mode 100644 index 0000000..77a4af4 --- /dev/null +++ b/memoapp/views/show.erb @@ -0,0 +1,14 @@ +

<%= @memo["title"] %>

+

<%= @memo["content"] %>

+
+
+ +
+
+ + +
+
+
+ +
diff --git a/wc.rb b/wc.rb index 487da2b..32d182c 100644 --- a/wc.rb +++ b/wc.rb @@ -8,7 +8,7 @@ def main total_stats = calculate_total_stats(file_stats) max_widths = calculate_max_widths(file_stats, total_stats) print_file_stats(file_stats, max_widths, options) - print_file_stats([['合計', total_stats]], max_widths, options) if sources.size > 1 + print_file_stats([{ filename: '合計', **total_stats }], max_widths, options) if sources.size > 1 end def parse_options @@ -26,31 +26,37 @@ end def collect_file_stats(sources) sources.map do |source| input = source.empty? ? ARGF.read : File.read(source) - stats = { lines: input.lines.count, words: input.split.size, bytes: input.bytesize } - [source, stats] + { filename: source, lines: input.lines.count, words: input.split.size, bytes: input.bytesize } end end def calculate_total_stats(file_stats) - file_stats.reduce({ lines: 0, words: 0, bytes: 0 }) do |total, (_, stats)| - total.merge(stats) { |_, a, b| a + b } + total_stats = { lines: 0, words: 0, bytes: 0 } + file_stats.each do |stats| + total_stats[:lines] += stats[:lines] + total_stats[:words] += stats[:words] + total_stats[:bytes] += stats[:bytes] end + total_stats end def calculate_max_widths(file_stats, total_stats) - (file_stats.map(&:last) + [total_stats]).each_with_object({ lines: 0, words: 0, bytes: 0 }) do |stats, max_widths| - max_widths.merge!(stats) { |_, max, stat| [max, stat.to_s.length].max } + all_stats = file_stats + [total_stats] + %i[lines words bytes].each_with_object({}) do |key, max_widths| + max_widths[key] = all_stats.map { |stats| stats[key].to_s.length }.max end end def format_result(stats, max_widths, options) - %i[lines words bytes].map { |key| stats[key].to_s.rjust(max_widths[key]) if options[key] }.compact.join(' ') + %i[lines words bytes].filter_map do |key| + stats[key].to_s.rjust(max_widths[key]) if options[key] + end.join(' ') end def print_file_stats(file_stats, max_widths, options) - file_stats.each do |source, stats| + file_stats.each do |stats| result = format_result(stats, max_widths, options) - puts "#{result} #{source}" + puts "#{result} #{stats[:filename]}" end end