pico 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.vimrc +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +33 -0
- data/gold_master_apps/tic_tac_toe/Gemfile +18 -0
- data/gold_master_apps/tic_tac_toe/Rakefile +3 -0
- data/gold_master_apps/tic_tac_toe/boot.rb +2 -0
- data/gold_master_apps/tic_tac_toe/config/application.rb +8 -0
- data/gold_master_apps/tic_tac_toe/config/environments/test.rb +3 -0
- data/gold_master_apps/tic_tac_toe/game/bad_move.rb +1 -0
- data/gold_master_apps/tic_tac_toe/game/game.rb +62 -0
- data/gold_master_apps/tic_tac_toe/game/make_move_command.rb +38 -0
- data/gold_master_apps/tic_tac_toe/game/memory_repository.rb +39 -0
- data/gold_master_apps/tic_tac_toe/test/game_test.rb +65 -0
- data/gold_master_apps/tic_tac_toe/test/reports/TEST-GameTest.xml +13 -0
- data/gold_master_apps/tic_tac_toe/test/test_helper.rb +7 -0
- data/lib/pico.rb +41 -0
- data/lib/pico/application.rb +120 -0
- data/lib/pico/autoloader.rb +131 -0
- data/lib/pico/context.rb +89 -0
- data/lib/pico/context/const_resolver.rb +80 -0
- data/lib/pico/pry_context.rb +71 -0
- data/lib/pico/rake.rb +15 -0
- data/lib/pico/ruse_extensions.rb +9 -0
- data/lib/pico/string_inflections.rb +30 -0
- data/lib/pico/test_runner.rb +27 -0
- data/lib/pico/version.rb +3 -0
- data/pico.gemspec +30 -0
- data/test/integration/autoloading_test.rb +47 -0
- data/test/support/fakes_filesystem.rb +182 -0
- data/test/support/tests_autoloading.rb +16 -0
- data/test/test_helper.rb +36 -0
- data/test/unit/application_test.rb +79 -0
- data/test/unit/autoloader_test.rb +68 -0
- data/test/unit/context_test.rb +80 -0
- metadata +202 -0
data/lib/pico/rake.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
task :env do
|
2
|
+
Pico.application.root = Rake.application.original_dir
|
3
|
+
end
|
4
|
+
|
5
|
+
desc "Open up a console"
|
6
|
+
task console: :env do
|
7
|
+
require "pico/pry_context"
|
8
|
+
Pico::PryContext.start!
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Run the test suite"
|
12
|
+
task test: :env do
|
13
|
+
require "pico/test_runner"
|
14
|
+
Pico::TestRunner.run!
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Pico
|
2
|
+
module StringInflections
|
3
|
+
refine String do
|
4
|
+
def to_camel_case
|
5
|
+
str = "_#{self}"
|
6
|
+
str.gsub!(%r{_[a-z]}) { |snake| snake.slice(1).upcase }
|
7
|
+
str.gsub!('/', '::')
|
8
|
+
str
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_snake_case
|
12
|
+
str = gsub '::', '/'
|
13
|
+
# Convert FOOBar => FooBar
|
14
|
+
str.gsub! %r{[[:upper:]]{2,}} do |uppercase|
|
15
|
+
bit = uppercase[0]
|
16
|
+
bit << uppercase[1...-1].downcase
|
17
|
+
bit << uppercase[-1]
|
18
|
+
bit
|
19
|
+
end
|
20
|
+
str.gsub! %r{[[:lower:]][[:upper:]]+[[:lower:]]} do |camel|
|
21
|
+
bit = camel[0]
|
22
|
+
bit << '_'
|
23
|
+
bit << camel[1..-1].downcase
|
24
|
+
end
|
25
|
+
str.downcase!
|
26
|
+
str
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Pico
|
2
|
+
module TestRunner
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def run!
|
6
|
+
Bundler.require :test
|
7
|
+
|
8
|
+
pid = fork do
|
9
|
+
Pico.shutdown! # For when we're inside pry
|
10
|
+
%w(test spec).each do |test_dir| load_test_files_in test_dir; end
|
11
|
+
Minitest.autorun
|
12
|
+
end
|
13
|
+
|
14
|
+
_, status = Process.wait2 pid
|
15
|
+
status.exitstatus == 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_test_files_in(test_dir)
|
19
|
+
path = Pico.application.root.join(test_dir)
|
20
|
+
return unless path.directory?
|
21
|
+
$LOAD_PATH << path
|
22
|
+
Dir[path.join("**/*_#{test_dir}.rb")].each do |test_file|
|
23
|
+
load test_file
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/pico/version.rb
ADDED
data/pico.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pico/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "pico"
|
8
|
+
spec.version = Pico::VERSION
|
9
|
+
spec.authors = ["ntl"]
|
10
|
+
spec.email = ["nathanladd+github@gmail.com"]
|
11
|
+
spec.summary = %q{Pico is a micro framework designed to get you some basic, essential functionality and then get out of your way.}
|
12
|
+
spec.description = %q{A very light weight framework for ruby designed to handle a small number of details common to most every application.}
|
13
|
+
spec.homepage = "https://github.com/ntl/pico"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^test/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "ruse", "~> 0.0.4"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
24
|
+
spec.add_development_dependency "colorize"
|
25
|
+
spec.add_development_dependency "fakefs"
|
26
|
+
spec.add_development_dependency "minitest"
|
27
|
+
spec.add_development_dependency "minitest-reporters"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "rake"
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AutoloadingTest < Minitest::Test
|
4
|
+
include FakesFilesystem
|
5
|
+
include TestsAutoloading
|
6
|
+
|
7
|
+
def test_simple_case
|
8
|
+
assert_equal 'hello from A::AA', Foo::A.references_aa
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_negative_case
|
12
|
+
assert_raises NameError do
|
13
|
+
Foo::A.references_abracadabra
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_deeply_nested_module_with_implicit_namespaces
|
18
|
+
assert_equal 'hello from C::CA::CAA::CAAA', Foo::A.references_caaa
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_reference_from_within_constant
|
22
|
+
assert_equal 'hello from A', Foo::D.references_a
|
23
|
+
assert_equal 'hello from B::BA', Foo::D.new.references_b_ba
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_invoking_method_inside_implicit_namespace_raises_error
|
27
|
+
exception = assert_raises NameError do
|
28
|
+
Foo::C.hello
|
29
|
+
end
|
30
|
+
assert_equal "uninitialized constant C (in Foo)", exception.message
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_raises_name_error_if_no_context_found
|
34
|
+
exception = assert_raises NameError do
|
35
|
+
Abracadabra
|
36
|
+
end
|
37
|
+
assert_equal "uninitialized constant Abracadabra", exception.message
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_application_autoload_paths
|
41
|
+
Pico.application.resolve_const 'A'
|
42
|
+
assert_equal 'hello from MyApp::A', MyApp::A.message
|
43
|
+
# Implicit namespace
|
44
|
+
assert_equal 'hello from MyApp::B::BA', MyApp::A.references_b_ba
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module FakesFilesystem
|
2
|
+
def before_setup
|
3
|
+
super
|
4
|
+
FakeFS::FileSystem.clear
|
5
|
+
FakeFS.activate!
|
6
|
+
World.build!
|
7
|
+
monkeypatch_assert!
|
8
|
+
end
|
9
|
+
|
10
|
+
def after_teardown
|
11
|
+
unmonkeypatch_assert!
|
12
|
+
FakeFS.deactivate!
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def monkeypatch_assert!
|
19
|
+
Minitest::Assertions.module_eval do
|
20
|
+
alias_method :orig_diff, :diff
|
21
|
+
def diff(*args)
|
22
|
+
FakeFS.without { orig_diff *args }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def unmonkeypatch_assert!
|
28
|
+
Minitest::Assertions.module_eval do
|
29
|
+
undef_method :diff
|
30
|
+
alias_method :diff, :orig_diff
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module World
|
35
|
+
extend self
|
36
|
+
|
37
|
+
def build!
|
38
|
+
Dir.mkdir '/foo'
|
39
|
+
|
40
|
+
File.write "/foo/a.rb", <<-FILE
|
41
|
+
module A
|
42
|
+
def self.message
|
43
|
+
"hello from A"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.references_aa
|
47
|
+
AA.message
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.references_abracadabra
|
51
|
+
Abracadabra.message
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.references_caaa
|
55
|
+
C::CA::CAA::CAAA.message
|
56
|
+
end
|
57
|
+
|
58
|
+
module AB
|
59
|
+
def self.message
|
60
|
+
"hello from A::AB"
|
61
|
+
end
|
62
|
+
|
63
|
+
module ABA
|
64
|
+
def self.message
|
65
|
+
"hello from A::AB::ABA"
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.references_abb
|
69
|
+
ABB.message
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
FILE
|
75
|
+
|
76
|
+
Dir.mkdir "/foo/a"
|
77
|
+
File.write "/foo/a/aa.rb", <<-FILE
|
78
|
+
module A
|
79
|
+
module AA
|
80
|
+
def self.message
|
81
|
+
"hello from A::AA"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
FILE
|
86
|
+
|
87
|
+
Dir.mkdir "/foo/a/ab"
|
88
|
+
File.write "/foo/a/ab/abb.rb", <<-FILE
|
89
|
+
module A
|
90
|
+
module AB
|
91
|
+
module ABB
|
92
|
+
def self.message
|
93
|
+
"hello from A::AB::ABB"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
FILE
|
99
|
+
|
100
|
+
Dir.mkdir "/foo/b"
|
101
|
+
File.write "/foo/b/ba.rb", <<-FILE
|
102
|
+
module B
|
103
|
+
module BA
|
104
|
+
def self.message
|
105
|
+
"hello from B::BA"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
FILE
|
110
|
+
|
111
|
+
Dir.mkdir "/foo/c"
|
112
|
+
Dir.mkdir "/foo/c/ca"
|
113
|
+
Dir.mkdir "/foo/c/ca/caa"
|
114
|
+
File.write "/foo/c/ca/caa/caaa.rb", <<-FILE
|
115
|
+
module C
|
116
|
+
module CA
|
117
|
+
module CAA
|
118
|
+
module CAAA
|
119
|
+
def self.message
|
120
|
+
"hello from C::CA::CAA::CAAA"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
FILE
|
127
|
+
|
128
|
+
File.write "/foo/d.rb", <<-FILE
|
129
|
+
class D
|
130
|
+
def self.references_a
|
131
|
+
A.message
|
132
|
+
end
|
133
|
+
def references_b_ba
|
134
|
+
B::BA.message
|
135
|
+
end
|
136
|
+
end
|
137
|
+
FILE
|
138
|
+
|
139
|
+
Dir.mkdir "/bar"
|
140
|
+
File.write "/bar/a.rb", <<-FILE
|
141
|
+
module A
|
142
|
+
def self.message
|
143
|
+
"hello from Bar::A"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
FILE
|
147
|
+
|
148
|
+
File.write "/bar/b.rb", <<-FILE
|
149
|
+
module B
|
150
|
+
def self.message
|
151
|
+
"hello from Bar::B"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
FILE
|
155
|
+
|
156
|
+
Dir.mkdir "/my_app"
|
157
|
+
Dir.mkdir "/my_app/lib"
|
158
|
+
File.write "/my_app/lib/a.rb", <<-FILE
|
159
|
+
module A
|
160
|
+
def self.message
|
161
|
+
"hello from MyApp::A"
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.references_b_ba
|
165
|
+
B::BA.message
|
166
|
+
end
|
167
|
+
end
|
168
|
+
FILE
|
169
|
+
|
170
|
+
Dir.mkdir "/my_app/lib/b"
|
171
|
+
File.write "/my_app/lib/b/ba.rb", <<-FILE
|
172
|
+
module B
|
173
|
+
module BA
|
174
|
+
def self.message
|
175
|
+
"hello from MyApp::B::BA"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
FILE
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module TestsAutoloading
|
2
|
+
def setup
|
3
|
+
@foo = Pico.define_context :Foo, root: "/foo"
|
4
|
+
@bar = Pico.define_context :Bar, root: '/bar', parent: :Foo
|
5
|
+
@app = Pico.define_application :MyApp, root: "/my_app" do
|
6
|
+
self.autoload_paths << 'lib'
|
7
|
+
end
|
8
|
+
Pico.boot!
|
9
|
+
assert_nil Pico::Autoloader.current_autoloader
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
assert_nil Pico::Autoloader.current_autoloader,
|
14
|
+
"Each test in this file must clean up after itself"
|
15
|
+
end
|
16
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "bundler"
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
require "minitest/autorun"
|
5
|
+
require "minitest/reporters"
|
6
|
+
|
7
|
+
require "colorize"
|
8
|
+
require "fakefs/safe"
|
9
|
+
require "ostruct"
|
10
|
+
require "pathname"
|
11
|
+
require "stringio"
|
12
|
+
|
13
|
+
Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new
|
14
|
+
|
15
|
+
require_relative "../lib/pico"
|
16
|
+
|
17
|
+
$LOAD_PATH << "test/support"
|
18
|
+
|
19
|
+
Minitest::Test.class_eval do
|
20
|
+
autoload :FakesFilesystem, "fakes_filesystem"
|
21
|
+
autoload :TestsAutoloading, "tests_autoloading"
|
22
|
+
|
23
|
+
def after_teardown
|
24
|
+
Pico.shutdown!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Binding
|
29
|
+
def method_missing(sym, *)
|
30
|
+
return super unless sym == :pry
|
31
|
+
FakeFS.without do
|
32
|
+
require 'pry'
|
33
|
+
pry
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ApplicationTest < Minitest::Test
|
4
|
+
def test_defining_an_application
|
5
|
+
Pico.define_application :Foo
|
6
|
+
Pico.boot!
|
7
|
+
refute_nil Pico.application
|
8
|
+
assert_equal :Foo, Pico.application.name
|
9
|
+
assert_equal Pathname(__FILE__).dirname, Pico.application.root
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_autoload_paths
|
13
|
+
Pico.define_application :Foo do
|
14
|
+
self.autoload_paths = %w(lib app)
|
15
|
+
end
|
16
|
+
|
17
|
+
assert_equal %w(lib app), Pico.application.autoload_paths
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_providing_objects
|
21
|
+
Pico.define_application :Foo do
|
22
|
+
provide as: 'foo' do :provided_foo; end
|
23
|
+
provide :provided_bar, as: 'bar'
|
24
|
+
provide 'MyClass', as: 'baz'
|
25
|
+
end
|
26
|
+
Pico.boot!
|
27
|
+
|
28
|
+
my_class = Class.new do def message; :provided_baz; end ; end
|
29
|
+
Object.const_set :MyClass, my_class
|
30
|
+
|
31
|
+
consumer = Class.new do
|
32
|
+
attr :foo, :bar, :baz, :ping
|
33
|
+
def initialize(foo, bar, baz, ping:)
|
34
|
+
@foo = foo ; @bar = bar ; @baz = baz; @ping = ping
|
35
|
+
end
|
36
|
+
end
|
37
|
+
Foo.const_set :Consumer, consumer
|
38
|
+
|
39
|
+
obj = Foo.build(:Consumer, ping: 'pong')
|
40
|
+
assert_equal :provided_foo, obj.foo
|
41
|
+
assert_equal :provided_bar, obj.bar
|
42
|
+
assert_equal :provided_baz, obj.baz.message
|
43
|
+
assert_equal 'pong', obj.ping
|
44
|
+
|
45
|
+
ensure
|
46
|
+
Object.send :remove_const, :MyClass
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_wraps_ruse_errors
|
50
|
+
Pico.define_application :Foo
|
51
|
+
Pico.boot!
|
52
|
+
|
53
|
+
consumer = Class.new do
|
54
|
+
attr :unmet_dep
|
55
|
+
def initialize(unmet_dep)
|
56
|
+
@unmet_dep = unmet_dep
|
57
|
+
end
|
58
|
+
end
|
59
|
+
Foo.const_set :Consumer, consumer
|
60
|
+
|
61
|
+
exception = assert_raises Pico::Exception do
|
62
|
+
Foo.build(:Consumer)
|
63
|
+
end
|
64
|
+
|
65
|
+
assert_equal "could not resolve dependency `unmet_dep'", exception.message
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_cannot_provide_object_as_block_and_arg
|
69
|
+
exception = assert_raises ArgumentError do
|
70
|
+
Pico.define_application :Foo do
|
71
|
+
provide :a_value, as: :foo do
|
72
|
+
:another_value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
assert_equal "cannot supply a block and a value", exception.message
|
78
|
+
end
|
79
|
+
end
|