duyoji_todo 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2b94f5c63e1af147d5b7717f08b1767fc004d0d8
4
+ data.tar.gz: 9b96544a4547ca86ff3b5f14e55a049652857f29
5
+ SHA512:
6
+ metadata.gz: fe6d846d42ed990583d2f2ed2b3f880a4545657317bd4f042bb6e3e9b81447302cbe3cd56c63f781348c490887c3aa476a4619fc78d7810a5624b2e37a7247d2
7
+ data.tar.gz: a60e761580d8e169d8db555b096a2c4962fbac05080fcff28911637cb899715aa66aaf0b31b6aa1d96c25b6089222c8d04b8b98411e97a6d2a681547541ed68b
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in duyoji_todo.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Tsuyoshi Maeda
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # DuyojiTodo
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'duyoji_todo'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install duyoji_todo
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require "yard"
3
+ #require 'yard/rake/yardoc_task'
4
+
5
+ YARD::Rake::YardocTask.new
data/bin/duyoji_todo ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'duyoji_todo'
4
+
5
+ DuyojiTodo::Command.run(ARGV)
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'duyoji_todo/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "duyoji_todo"
8
+ spec.version = DuyojiTodo::VERSION
9
+ spec.authors = ["Tsuyoshi Maeda"]
10
+ spec.email = ["oasis5tsuyoshi@gmail.com"]
11
+ spec.description = %q{Perfect Ruby chapter15}
12
+ spec.summary = %q{Perfect Ruby chapter15}
13
+ spec.homepage = "http://duyoji.hatenablog.com/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activerecord", "~> 3.2.0"
22
+ spec.add_dependency "sqlite3", "~> 1.3.0"
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "yard", "~> 0.8"
26
+ spec.add_development_dependency "redcarpet", "~> 2.2"
27
+
28
+ end
@@ -0,0 +1,9 @@
1
+ require "duyoji_todo/command"
2
+ require "duyoji_todo/command/options"
3
+ require "duyoji_todo/db"
4
+ require "duyoji_todo/task"
5
+ require "duyoji_todo/version"
6
+
7
+ module DuyojiTodo
8
+ # Your code goes here...
9
+ end
@@ -0,0 +1,106 @@
1
+ #coding: utf-8
2
+
3
+ module DuyojiTodo
4
+
5
+ # コマンドラインベースの処理を行うクラスです
6
+ # @author Tsuyoshi Maeda
7
+ class Command
8
+
9
+ class << self
10
+ def run(argv)
11
+ new(argv).execute
12
+ end
13
+ end
14
+
15
+ def initialize(argv)
16
+ @argv = argv
17
+ end
18
+
19
+ def execute
20
+ options = Options.parse!(@argv)
21
+ sub_command = options.delete(:command)
22
+
23
+ #puts options
24
+
25
+ DB.prepare
26
+
27
+ tasks = case sub_command
28
+ when 'create'
29
+ create_task(options[:name], options[:content])
30
+ when 'delete'
31
+ delete_task(options[:id])
32
+ when 'update'
33
+ update_task(options.delete(:id), options)
34
+ when 'list'
35
+ find_tasks(options[:status])
36
+ end
37
+
38
+ display_tasks tasks
39
+
40
+ rescue => e
41
+ abort "Error: #{e.message}"
42
+
43
+ end
44
+
45
+ def create_task(name, content)
46
+ # タスク作成時のstatusはデフォルト値が使われNOT_YETとなる
47
+ Task.create!(name: name, content: content).reload
48
+ end
49
+
50
+ def delete_task(id)
51
+ task = Task.find(id)
52
+ task.destroy
53
+ end
54
+
55
+ def update_task(id, attributes)
56
+ if status_name = attributes[:status]
57
+ attributes[:status] = DuyojiTodo::Task::STATUS.fetch(status_name.upcase)
58
+ end
59
+
60
+ task = Task.find(id)
61
+ task.update_attributes! attributes
62
+
63
+ task.reload
64
+ end
65
+
66
+ def find_tasks(status_name)
67
+ all_tasks = Task.order('created_at DESC')
68
+
69
+ if status_name
70
+ status = DuyojiTodo::Task::STATUS.fetch(status_name.upcase)
71
+ all_tasks.status_is(status)
72
+ else
73
+ all_tasks
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ # タスクの表示
80
+ def display_tasks(tasks)
81
+ header = display_format('ID', 'Name', 'Content', 'Status')
82
+
83
+ puts header
84
+ puts '-' * header.size
85
+ Array(tasks).each do |task|
86
+ puts display_format(task.id, task.name, task.content, task.status_name)
87
+ end
88
+
89
+ end
90
+
91
+ # タスク表示のフォーマット化
92
+ def display_format(id, name, content, status)
93
+ name_length = 20 - full_width_count(name)
94
+ content_length = 40 - full_width_count(content)
95
+
96
+ [ id.to_s.rjust(4), name.ljust(name_length), content.ljust(content_length), status.ljust(8) ].join(' | ')
97
+ end
98
+
99
+ # リスト表示の際の文字調整
100
+ def full_width_count(string)
101
+ string.each_char.select{ |char| !( /[ -~.]/.match(char) ) }.count
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,119 @@
1
+ #coding: utf-8
2
+
3
+ require "optparse"
4
+
5
+ module DuyojiTodo
6
+
7
+ class Command
8
+
9
+ module Options
10
+
11
+ def self.parse!(argv)
12
+ options = {}
13
+
14
+ # サブコマンドなどのOptionParserを定義
15
+ sub_command_parsers = create_sub_command_parsers(options)
16
+ command_parser = create_command_parser
17
+
18
+
19
+ # 引数解析を行う
20
+ begin
21
+ command_parser.order!(argv)
22
+ options[:command] = argv.shift
23
+ sub_command_parsers[ options[:command] ].parse!(argv)
24
+
25
+ #updateとdeleteの場合は
26
+ if %w(update delete).include?( options[:command] )
27
+ raise ArgumentError, "#{options[:command]} id not found." if argv.empty?
28
+ options[:id] = Integer(argv.first)
29
+ end
30
+ rescue OptionParser::MissingArgument => e
31
+ abort "OptionParserMissingArgument : #{e.message}"
32
+ rescue OptionParser::InvalidOption => e
33
+ abort "OptionParserInvalidOption : #{e.message}"
34
+ rescue ArgumentError => e
35
+ abort "ArgumentError : #{e.message}"
36
+ end
37
+
38
+ options
39
+ end
40
+
41
+ def self.create_sub_command_parsers(options)
42
+ # サブコマンドの処理をする際に、未定義のkeyを指定されたら例外を発生させる
43
+ sub_command_parsers = Hash.new do |k, v|
44
+ raise ArgumentError, "'#{v}' is not duyoji_todo sub command."
45
+ end
46
+
47
+ # サブコマンド用の定義
48
+ sub_command_parsers['create'] = OptionParser.new do |opt|
49
+ opt.banner = "Usage: create <args>"
50
+ opt.on('-n', '--name=VAL', 'task name') { |v| options[:name] = v }
51
+ opt.on('-c', '--content=VAL', 'task content') { |v| options[:content] = v }
52
+ opt.on_tail('-h', '--help', 'Show this message') { |v| help_sub_command(opt) }
53
+ end
54
+
55
+ sub_command_parsers['list'] = OptionParser.new do |opt|
56
+ opt.banner = "Usage: list <args>"
57
+ opt.on('-s', '--status=VAL', 'search status') { |v| options[:status] = v }
58
+ opt.on_tail('-h', '--help', 'Show this message') { |v| help_sub_command(opt) }
59
+ end
60
+
61
+ sub_command_parsers['update'] = OptionParser.new do |opt|
62
+ opt.banner = "Usage: update id <args>"
63
+ opt.on('-n', '--name=VAL', 'update name') { |v| options[:name] = v }
64
+ opt.on('-c', '--content=VAL', 'update content') { |v| options[:content] = v }
65
+ opt.on('-s', '--status=VAL', 'update status') { |v| options[:status] = v }
66
+ opt.on_tail('-h', '--help', 'Show this message') { |v| help_sub_command(opt) }
67
+ end
68
+
69
+ sub_command_parsers['delete'] = OptionParser.new do |opt|
70
+ opt.banner = "Usage: delete id"
71
+ opt.on_tail('-h', '--help', 'Show this message') { |v| help_sub_command(opt) }
72
+ end
73
+
74
+ sub_command_parsers
75
+ end
76
+
77
+ def self.create_command_parser
78
+ # サブコマンド以外の定数の定義
79
+ OptionParser.new do |opt|
80
+ sub_command_help = [
81
+ {name: 'create -n name -c content', summary: 'Create Todo Task'},
82
+ {name: 'update id -n name -c content -s status', summary: 'Update Todo Task'},
83
+ {name: 'list -s status', summary: 'List Todo Task'},
84
+ {name: 'delete id', summary: 'Delete Todo Task'},
85
+ ]
86
+
87
+ opt.banner = "Usage: #{opt.program_name} [-h|--help] [-v|--version] <command> [<args>]"
88
+ opt.separator ''
89
+ opt.separator "#{opt.program_name} Available Commands:"
90
+
91
+ sub_command_help.each do |command|
92
+ opt.separator [ opt.summary_indent, command[:name].ljust(40), command[:summary] ].join(' ')
93
+ end
94
+
95
+ opt.on_head('-h', '--help', 'Show this version') do |v|
96
+ puts opt.help
97
+ exit
98
+ end
99
+
100
+ opt.on_head('-v', '--version', 'Show program version') do |v|
101
+ opt.version = DuyojiTodo::VERSION
102
+ puts opt.ver
103
+ exit
104
+ end
105
+ end
106
+ end
107
+
108
+ # サブコマンドのヘルプ情報
109
+ def self.help_sub_command(parser)
110
+ puts parser.help
111
+ exit
112
+ end
113
+
114
+ private_class_method :create_sub_command_parsers, :create_command_parser, :help_sub_command
115
+ end
116
+
117
+ end
118
+
119
+ end
@@ -0,0 +1,52 @@
1
+ ##coding: utf-8
2
+
3
+ require 'fileutils'
4
+ require 'active_record'
5
+
6
+ module DuyojiTodo
7
+
8
+
9
+ # データベースへの接続処理を扱うモジュール
10
+ # @author Tsuyoshi Maeda
11
+ module DB
12
+
13
+ # データベースへの接続とテーブルの作成を行う
14
+ # @return [void]
15
+ def self.prepare
16
+ database_path = File.join(ENV['HOME'], '.duyoji_todo', 'duyoji_todo.sqlite3')
17
+
18
+ connect_database database_path
19
+ create_table_if_not_exists database_path
20
+ end
21
+
22
+ def self.connect_database(path)
23
+ spec = {adapter: 'sqlite3', database: path}
24
+ ActiveRecord::Base.establish_connection spec
25
+ end
26
+
27
+ def self.create_table_if_not_exists(path)
28
+ create_database_path path
29
+
30
+ connection = ActiveRecord::Base.connection
31
+
32
+ return if connection.table_exists?(:tasks)
33
+
34
+
35
+ connection.create_table :tasks do |t|
36
+ t.column :name, :string, null: false
37
+ t.column :content, :text, null: false
38
+ t.column :status, :integer, default: 0, null: false
39
+ t.timestamps
40
+ end
41
+ connection.add_index :tasks, :status
42
+ connection.add_index :tasks, :created_at
43
+ end
44
+
45
+ def self.create_database_path(path)
46
+ FileUtils.mkdir_p File.dirname(path)
47
+ end
48
+
49
+ private_class_method :connect_database, :create_table_if_not_exists, :create_database_path
50
+ end
51
+
52
+ end
@@ -0,0 +1,37 @@
1
+ #coding: utf-8
2
+
3
+ require 'active_record'
4
+
5
+ module DuyojiTodo
6
+
7
+ # tasksテーブルを表現するモデルクラスです
8
+ # @author Tsuyoshi Maeda
9
+ class Task < ActiveRecord::Base
10
+
11
+ NOT_YET = 0 # タスクが完了していない
12
+ DONE = 1 # タスクが完了した
13
+ PENDING = 2 # 保留状態
14
+
15
+ # ステータ薄の名称と数値の組み合わせの値
16
+ STATUS = {
17
+ 'NOT_YET' => NOT_YET,
18
+ 'DONE' => DONE,
19
+ 'PENDING' => PENDING
20
+ }.freeze
21
+
22
+ # ステータスの条件のよって取得する値を切り替える
23
+ scope :status_is, ->(status) { where(status: status) }
24
+
25
+
26
+ # バリデート
27
+ validates :name, presence: true, length: {maximum: 140}
28
+ validates :content, presence: true
29
+ validates :status, numericality: true, inclusion: {in: STATUS.values}
30
+
31
+ def status_name
32
+ STATUS.key(self.status)
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,3 @@
1
+ module DuyojiTodo
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: duyoji_todo
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tsuyoshi Maeda
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: redcarpet
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '2.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '2.2'
97
+ description: Perfect Ruby chapter15
98
+ email:
99
+ - oasis5tsuyoshi@gmail.com
100
+ executables:
101
+ - duyoji_todo
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - .gitignore
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - bin/duyoji_todo
111
+ - duyoji_todo.gemspec
112
+ - lib/duyoji_todo.rb
113
+ - lib/duyoji_todo/command.rb
114
+ - lib/duyoji_todo/command/options.rb
115
+ - lib/duyoji_todo/db.rb
116
+ - lib/duyoji_todo/task.rb
117
+ - lib/duyoji_todo/version.rb
118
+ homepage: http://duyoji.hatenablog.com/
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.1.11
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Perfect Ruby chapter15
142
+ test_files: []
143
+ has_rdoc: