pico 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.vimrc +3 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +29 -0
  7. data/Rakefile +33 -0
  8. data/gold_master_apps/tic_tac_toe/Gemfile +18 -0
  9. data/gold_master_apps/tic_tac_toe/Rakefile +3 -0
  10. data/gold_master_apps/tic_tac_toe/boot.rb +2 -0
  11. data/gold_master_apps/tic_tac_toe/config/application.rb +8 -0
  12. data/gold_master_apps/tic_tac_toe/config/environments/test.rb +3 -0
  13. data/gold_master_apps/tic_tac_toe/game/bad_move.rb +1 -0
  14. data/gold_master_apps/tic_tac_toe/game/game.rb +62 -0
  15. data/gold_master_apps/tic_tac_toe/game/make_move_command.rb +38 -0
  16. data/gold_master_apps/tic_tac_toe/game/memory_repository.rb +39 -0
  17. data/gold_master_apps/tic_tac_toe/test/game_test.rb +65 -0
  18. data/gold_master_apps/tic_tac_toe/test/reports/TEST-GameTest.xml +13 -0
  19. data/gold_master_apps/tic_tac_toe/test/test_helper.rb +7 -0
  20. data/lib/pico.rb +41 -0
  21. data/lib/pico/application.rb +120 -0
  22. data/lib/pico/autoloader.rb +131 -0
  23. data/lib/pico/context.rb +89 -0
  24. data/lib/pico/context/const_resolver.rb +80 -0
  25. data/lib/pico/pry_context.rb +71 -0
  26. data/lib/pico/rake.rb +15 -0
  27. data/lib/pico/ruse_extensions.rb +9 -0
  28. data/lib/pico/string_inflections.rb +30 -0
  29. data/lib/pico/test_runner.rb +27 -0
  30. data/lib/pico/version.rb +3 -0
  31. data/pico.gemspec +30 -0
  32. data/test/integration/autoloading_test.rb +47 -0
  33. data/test/support/fakes_filesystem.rb +182 -0
  34. data/test/support/tests_autoloading.rb +16 -0
  35. data/test/test_helper.rb +36 -0
  36. data/test/unit/application_test.rb +79 -0
  37. data/test/unit/autoloader_test.rb +68 -0
  38. data/test/unit/context_test.rb +80 -0
  39. metadata +202 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fba9d61978a88aaa52222819d4440c4c5b43b40a
4
+ data.tar.gz: ddd4b6989de2f9c71514b78dcdf51a7751f59535
5
+ SHA512:
6
+ metadata.gz: 94f4ce13c6059ead5fd19eb760bd7508346a8091d98b0aab6fe7992a26fe646ba459bcfd83731bd403d542f7cc2be16238b366b4f54f5b3fd232339bb3e1af47
7
+ data.tar.gz: 0d39efdb6fa92f6fb6452e710dcdd3b99ef8c6c1601266bbcec3cc4e27bb64a79ffb134303a6a4b4a58a95ea98c1d89edc8d581ccbb9193fa8fc6a90bb5d9fa6
data/.gitignore ADDED
@@ -0,0 +1,24 @@
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
18
+ vendor/ruby
19
+ bin
20
+ !bin/pico
21
+ tags
22
+ .gems
23
+ .ruby-version
24
+ .rbenv-gemsets
data/.vimrc ADDED
@@ -0,0 +1,3 @@
1
+ map <F5> :call system("tmux resize -y 20 -t 1 && tmux send -t1 'rake && tmux resize -Z -t 0' c-j") <CR>
2
+ map <F6> :call system("tmux resize -Z -t 0") <CR>
3
+ map <F7> :call system("tmux resize -y 40 -t 1") <CR>
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pico.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 ntl
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
+ # Pico
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'pico'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install pico
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/pico/fork )
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,33 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = 'test/**/*_test.rb'
6
+ t.libs << 'test'
7
+ end
8
+
9
+ desc "Update ctags"
10
+ task :ctags do
11
+ `ctags -R --languages=Ruby --totals -f tags`
12
+ end
13
+
14
+ desc "Run the internal build plus all gold master apps"
15
+ namespace :test do
16
+ task :all do
17
+ Rake::Task['test'].invoke
18
+ Rake::Task['test:gold_master_apps'].invoke
19
+ end
20
+
21
+ task :gold_master_apps do
22
+ Dir['gold_master_apps/*'].each do |app_dir|
23
+ puts "\n\nRunning tests for gold master app `#{File.basename(app_dir)}'"
24
+ Dir.chdir app_dir do
25
+ process = fork do exec "bin/rake" end
26
+ Process.wait process
27
+ exit $?.exitstatus unless $?.exitstatus == 0
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ task default: 'test:all'
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby '2.1.1'
4
+
5
+ gem 'pico', path: File.expand_path('../../..', __FILE__)
6
+
7
+ gem 'rake'
8
+
9
+ group :test do
10
+ gem 'minitest'
11
+ gem 'minitest-reporters'
12
+ end
13
+
14
+ group :pry do
15
+ gem 'pry'
16
+ gem 'pry-byebug'
17
+ gem 'pry-stack_explorer'
18
+ end
@@ -0,0 +1,3 @@
1
+ require_relative "config/application"
2
+
3
+ task default: :test
@@ -0,0 +1,2 @@
1
+ load File.expand_path("../config/application.rb", __FILE__)
2
+ Pico.boot!
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+ Bundler.require :default
4
+
5
+ Pico.define_application :TicTacToe do |config|
6
+ config.autoload_paths = %w(game users)
7
+ config.provide 'MemoryRepository', as: :repository
8
+ end
@@ -0,0 +1,3 @@
1
+ Pico.application.configure do |config|
2
+ config.provide
3
+ end
@@ -0,0 +1 @@
1
+ BadMove = Class.new StandardError
@@ -0,0 +1,62 @@
1
+ class Game
2
+ attr :repository, :id, :board, :player, :winner
3
+
4
+ def initialize(repository:, id:, board:, player:)
5
+ @id = id
6
+ @repository = repository
7
+ @board = board
8
+ @player = player
9
+ end
10
+
11
+ def winner
12
+ RUNS_OF_THREE.each do |tiles|
13
+ %i(player_1 player_2).each do |player|
14
+ return player if tiles.all? { |at| fetch_tile(at) == player }
15
+ end
16
+ end
17
+ nil
18
+ end
19
+
20
+ def finished?
21
+ winner ? true : false
22
+ end
23
+
24
+ def make_move!(as:, at:)
25
+ MakeMoveCommand.new(game: self, player: as, position: at).apply!
26
+ end
27
+
28
+ def fetch_tile(position)
29
+ row, col = BOARD_MAP.fetch(position)
30
+ board.fetch(row).fetch(col)
31
+ end
32
+
33
+ def apply_move!(position:)
34
+ row, col = BOARD_MAP.fetch(position)
35
+ board.fetch(row)[col] = player
36
+ @player = { player_1: :player_2, player_2: :player_1 }.fetch(player)
37
+ repository.store self
38
+ end
39
+
40
+ BOARD_MAP = {
41
+ top_left: [0, 0],
42
+ top: [0, 1],
43
+ top_right: [0, 2],
44
+ left: [1, 0],
45
+ center: [1, 1],
46
+ right: [1, 2],
47
+ bottom_left: [2, 0],
48
+ bottom: [2, 1],
49
+ bottom_right: [2, 2],
50
+ }
51
+
52
+ RUNS_OF_THREE = [
53
+ [:top_left, :center, :bottom_right],
54
+ [:top_right, :center, :bottom_left],
55
+ [:top_left, :left, :bottom_left],
56
+ [:top, :center, :bottom],
57
+ [:top_right, :right, :bottom_right],
58
+ [:top_left, :top, :top_right],
59
+ [:left, :center, :right],
60
+ [:bottom_left, :bottom, :bottom_right],
61
+ ]
62
+ end
@@ -0,0 +1,38 @@
1
+ class MakeMoveCommand
2
+ attr :game, :game_id, :player, :position, :repository
3
+
4
+ def initialize(game_id:, repository:, player:, position:)
5
+ @game_id = game_id
6
+ @player = player
7
+ @position = position
8
+ @repository = repository
9
+ end
10
+
11
+ def apply!
12
+ @game = repository.find(game_id)
13
+
14
+ validate_game_is_in_progress
15
+ validate_player
16
+ validate_tile
17
+
18
+ game.apply_move! position: position
19
+ end
20
+
21
+ def tile
22
+ game.fetch_tile position
23
+ end
24
+
25
+ def validate_game_is_in_progress
26
+ raise BadMove, "Game has already ended!" if game.finished?
27
+ end
28
+
29
+ def validate_player
30
+ raise BadMove, "It is #{game.player}'s turn" unless player == game.player
31
+ end
32
+
33
+ def validate_tile
34
+ unless tile == :free
35
+ raise BadMove, "Tile at #{position} is already occupied!"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ class MemoryRepository
2
+ class << self
3
+ def boards
4
+ @boards ||= {}
5
+ end
6
+ end
7
+
8
+ def boards
9
+ self.class.boards
10
+ end
11
+
12
+ def create(id:)
13
+ boards[id] = {
14
+ player: :player_1,
15
+ board: [
16
+ [:free, :free, :free],
17
+ [:free, :free, :free],
18
+ [:free, :free, :free],
19
+ ],
20
+ }
21
+ end
22
+
23
+ def find(id)
24
+ data = boards.fetch id
25
+ TicTacToe::Game.new(
26
+ id: id,
27
+ repository: self,
28
+ player: data[:player],
29
+ board: data[:board].dup,
30
+ )
31
+ end
32
+
33
+ def store(game)
34
+ boards[game.id] = {
35
+ player: game.player,
36
+ board: game.board.dup,
37
+ }
38
+ end
39
+ end
@@ -0,0 +1,65 @@
1
+ require 'test_helper'
2
+
3
+ TicTacToe::MakeMoveCommand
4
+
5
+ class GameTest < Minitest::Test
6
+ def setup
7
+ @game_id = 'abcdef-0123-4567-abcdefghi'
8
+ TicTacToe::MemoryRepository.new.create(id: @game_id)
9
+ end
10
+
11
+ def test_initial_board
12
+ assert_equal [[:free, :free, :free],[:free, :free, :free],[:free, :free, :free]], game.board
13
+ refute game.finished?
14
+ end
15
+
16
+ def test_making_valid_move
17
+ make_move! player: :player_1, position: :center
18
+
19
+ assert_equal [[:free, :free, :free],[:free, :player_1, :free],[:free, :free, :free]], game.board
20
+ end
21
+
22
+ def test_making_move_as_wrong_player
23
+ exception = assert_raises TicTacToe::BadMove do
24
+ make_move! player: :player_2, position: :center
25
+ end
26
+ assert_equal "It is player_1's turn", exception.message
27
+ end
28
+
29
+ def test_must_pick_free_space
30
+ make_move! player: :player_1, position: :center
31
+
32
+ exception = assert_raises TicTacToe::BadMove do
33
+ make_move! player: :player_2, position: :center
34
+ end
35
+ assert_equal "Tile at center is already occupied!", exception.message
36
+ end
37
+
38
+ def test_three_in_a_row_ends_game
39
+ make_move! player: :player_1, position: :left
40
+ make_move! player: :player_2, position: :right
41
+ make_move! player: :player_1, position: :bottom
42
+ make_move! player: :player_2, position: :top_right
43
+ make_move! player: :player_1, position: :bottom_left
44
+ make_move! player: :player_2, position: :top_left
45
+ make_move! player: :player_1, position: :bottom_right
46
+
47
+ assert game.finished?
48
+ assert_equal :player_1, game.winner
49
+
50
+ exception = assert_raises TicTacToe::BadMove do
51
+ make_move! player: :player_2, position: :top
52
+ end
53
+ assert_equal "Game has already ended!", exception.message
54
+ end
55
+
56
+ private
57
+
58
+ def make_move!(**params)
59
+ TicTacToe.build('MakeMoveCommand', game_id: @game_id, **params).apply!
60
+ end
61
+
62
+ def game
63
+ TicTacToe::MemoryRepository.new.find @game_id
64
+ end
65
+ end
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <testsuite name="GameTest" skipped="0" failures="0" errors="0" tests="5" assertions="11" time="0.004318000000000001">
3
+ <testcase name="test_making_valid_move" classname="GameTest" assertions="1" time="0.001956">
4
+ </testcase>
5
+ <testcase name="test_initial_board" classname="GameTest" assertions="2" time="5.2e-05">
6
+ </testcase>
7
+ <testcase name="test_three_in_a_row_ends_game" classname="GameTest" assertions="4" time="0.001909">
8
+ </testcase>
9
+ <testcase name="test_must_pick_free_space" classname="GameTest" assertions="2" time="0.000263">
10
+ </testcase>
11
+ <testcase name="test_making_move_as_wrong_player" classname="GameTest" assertions="2" time="0.000138">
12
+ </testcase>
13
+ </testsuite>
@@ -0,0 +1,7 @@
1
+ require 'minitest'
2
+ require 'minitest/reporters'
3
+ require 'minitest/autorun'
4
+
5
+ load File.expand_path("../../boot.rb", __FILE__)
6
+
7
+ Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new
data/lib/pico.rb ADDED
@@ -0,0 +1,41 @@
1
+ require "pico/string_inflections"
2
+ require "pico/autoloader"
3
+ require "pico/context"
4
+ require "pico/application"
5
+ require "pico/version"
6
+
7
+ require "ruse"
8
+ require "pico/ruse_extensions"
9
+
10
+ if defined? Rake
11
+ require "pico/rake"
12
+ end
13
+
14
+ module Pico
15
+ extend self
16
+
17
+ attr :application, :contexts
18
+ @contexts = {}
19
+
20
+ def define_application(name, **params, &block)
21
+ contexts[name] = @application = Application.new(name, **params, &block)
22
+ end
23
+
24
+ def define_context(name, **params)
25
+ contexts[name] = Context.new(name, **params)
26
+ end
27
+
28
+ def boot!
29
+ contexts.each_value(&:boot!)
30
+ end
31
+
32
+ def shutdown!
33
+ contexts.each_value do |context|
34
+ context.shutdown! if context.booted?
35
+ end
36
+ contexts.clear
37
+ end
38
+
39
+ Error = Class.new StandardError
40
+ Exception = Class.new Error
41
+ end