from __future__ import absolute_import, print_function, division
import abc
import sys
import json
import attr
from attr import asdict
from typing import Callable, IO, cast
__author__ = 'Andrew Elgert, James Ladd'
__credits__ = ['Andrew Elgert', 'James Ladd']
@attr.s
[docs]class MovieValue(object):
title = attr.ib(default='')
director = attr.ib(default='')
[docs]class Movie(metaclass=abc.ABCMeta):
@abc.abstractmethod
[docs] def if_directed_by_do(self, director: str, action: Callable[['Movie'], None]) -> 'Movie':
"""Perform :action if movie directed by :director"""
@abc.abstractmethod
[docs] def if_title_do(self, title: str, action: Callable[['Movie'], None]) -> 'Movie':
"""Perform :action if movie title is :title"""
@abc.abstractmethod
@abc.abstractmethod
[docs] def print_on(self, stream: IO[str]):
"""Print movie onto :stream"""
# TODO: Smell. Refactor to have "MoviePrinter" take care of formatting + printing using factories
@abc.abstractmethod
[docs]class MovieFinder(metaclass=abc.ABCMeta):
@abc.abstractmethod
[docs] def find_all_and_apply(self, action: Callable[[Movie], None]) -> 'MovieFinder':
"""Find all movies and apply :action"""
[docs]class MovieLister(metaclass=abc.ABCMeta):
@abc.abstractmethod
[docs] def apply_to_movies_directed_by(self, action: Callable[[Movie], None], director: str) -> 'MovieLister':
"""Execute :action on movies directed by by :director"""
[docs]class MoviesClient(metaclass=abc.ABCMeta):
@abc.abstractmethod
[docs] def append(self, movie: Movie) -> 'MoviesClient':
"""Append :movie onto stream using :formatter"""
[docs]class ExampleMovieLister(MovieLister):
def __init__(self, finder: MovieFinder):
self._finder = finder
[docs] def apply_to_movies_directed_by(self, action: Callable[[Movie], None], director: str):
self._finder.find_all_and_apply(lambda movie: movie.if_directed_by_do(director, action))
return self
[docs]class ExampleMovie(Movie):
def __init__(self, title: str, director: str):
self._title = title
self._director = director
self._formatted_movie = ''
[docs] def if_directed_by_do(self, director: str, action: Callable[[Movie], None]):
if self._director == director:
action(self)
return self
[docs] def if_title_do(self, title: str, action: Callable[[Movie], None]):
if self._title == title:
action(self)
return self
[docs] def print_on(self, stream: IO[str]):
stream.write(self._formatted_movie)
[docs]class ExampleMovieFinder(MovieFinder):
_MOVIES = [
ExampleMovie('Star Wars', director='George Lucas'),
ExampleMovie('Lost Highway', director='David Lynch'),
ExampleMovie('Naked Lunch', director='David Cronenberg'),
ExampleMovie('Mulholland Dr', director='David Lynch'),
ExampleMovie('The Adventures of Buckaroo Banzai Across the 8th Dimension', director='W.D. Richter'),
ExampleMovie('Wild At Heart', director='David Lynch'),
]
[docs] def find_all_and_apply(self, selector: Callable[[Movie], None]):
for movie in self._MOVIES:
selector(movie)
[docs]class ExampleMoviesClientStreamAdaptor(MoviesClient):
def __init__(self, stream: IO[str], formatter: MovieFormatter):
self._stream = stream
self._formatter = formatter
[docs] def append(self, movie: Movie):
movie.format_with(self._formatter).print_on(self._stream)
[docs]class ExampleMoviesClientFileAdaptor(MoviesClient):
def __init__(self, file_path: str, formatter: MovieFormatter):
self._file_path = file_path
self._formatter = formatter
[docs] def append(self, movie: Movie):
with cast(IO[str], open(self._file_path, 'a')) as f:
f.truncate()
movie.format_with(self._formatter).print_on(f)
if __name__ == '__main__':
ExampleMovieLister(ExampleMovieFinder()).apply_to_movies_directed_by(
lambda movie: ExampleMoviesClientStreamAdaptor(sys.stdout, JSONMovieFormatter()).append(movie),
'George Lucas'
)
ExampleMovieLister(ExampleMovieFinder()).apply_to_movies_directed_by(
(lambda formatter: lambda movie: ExampleMoviesClientStreamAdaptor(sys.stdout, formatter).append(movie))(
JSONArrayMovieFormatter()
),
'David Lynch'
)
ExampleMovieLister(ExampleMovieFinder()).apply_to_movies_directed_by(
lambda movie: ExampleMoviesClientFileAdaptor("../movies.txt", SimpleStringMovieFormatter()).append(movie),
'David Lynch'
)