pico 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
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,9 @@
1
+ Ruse::TypeResolver.class_eval do
2
+ def load_type(type_name)
3
+ @injector.pico_context.resolve_const type_name
4
+ end
5
+ end
6
+
7
+ Ruse::Injector.class_eval do
8
+ attr_accessor :pico_context
9
+ 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
@@ -0,0 +1,3 @@
1
+ module Pico
2
+ VERSION = "0.0.1"
3
+ end
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
@@ -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