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
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